From 75cf19fb320f7867cf2c2a6f68642cf98b10c844 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Fri, 18 Jul 2025 14:43:20 +0800 Subject: [PATCH 01/23] =?UTF-8?q?[fit]=20=E5=AE=9E=E7=8E=B0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E6=A0=A1=E9=AA=8C=E6=8F=92=E4=BB=B6=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81javax=EF=BC=8CJakarta=E6=A0=87=E5=87=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fit-hibernate-validation-jakarta/pom.xml | 114 ++++ .../validation/ValidationHandler.java | 104 +++ .../src/main/resources/application.yaml | 4 + .../ValidationDataControllerTest.java | 90 +++ .../validation/ValidationHandlerTest.java | 621 ++++++++++++++++++ .../fitframework/validation/data/Company.java | 46 ++ .../validation/data/Employee.java | 55 ++ .../validation/data/GroupValidateService.java | 55 ++ .../validation/data/ValidateService.java | 202 ++++++ .../data/ValidationDataController.java | 42 ++ .../validation/data/ValidationTestData.java | 297 +++++++++ .../plugins/fit-hibernate-validation/pom.xml | 114 ++++ .../validation/ValidationHandler.java | 105 +++ .../src/main/resources/application.yaml | 4 + .../ValidationDataControllerTest.java | 91 +++ .../validation/ValidationHandlerTest.java | 620 +++++++++++++++++ .../fitframework/validation/data/Company.java | 46 ++ .../validation/data/Employee.java | 55 ++ .../validation/data/GroupValidateService.java | 55 ++ .../validation/data/ValidateService.java | 202 ++++++ .../data/ValidationDataController.java | 42 ++ .../validation/data/ValidationTestData.java | 297 +++++++++ .../fit/java/fit-builtin/plugins/pom.xml | 2 + 23 files changed, 3263 insertions(+) create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/resources/application.yaml create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/resources/application.yaml create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Company.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Employee.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidateService.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml new file mode 100644 index 000000000..3dc97b234 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml @@ -0,0 +1,114 @@ + + + 4.0.0 + + + org.fitframework.plugin + fit-plugin-parent + 3.6.0-SNAPSHOT + + + fit-hibernate-validation-jakarta + + FIT Hibernate Validation Jakarta + FIT Framework Hibernate Validation module provides Validation for args. + + https://github.com/ModelEngine-Group/fit-framework + + + + 9.0.1.Final + + + + + + + org.fitframework + fit-api + + + + + org.hibernate.validator + hibernate-validator + ${hibernate.version} + + + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-core + test + + + org.assertj + assertj-core + test + + + org.fitframework + fit-test-framework + test + + + com.h2database + h2 + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + + copy-dependencies + + + ../../../../../../build/shared/ + jakarta.validation + + + + + + org.fitframework + fit-build-maven-plugin + + system + 1 + + + + org.apache.maven.plugins + maven-antrun-plugin + + + package + + + + + + + run + + + + + + + + diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java new file mode 100644 index 000000000..66dbf8b38 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation; + +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Scope; +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.aop.annotation.Aspect; +import modelengine.fitframework.aop.annotation.Before; +import modelengine.fitframework.ioc.annotation.PreDestroy; + +import org.hibernate.validator.HibernateValidator; +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Parameter; +import java.util.Arrays; +import java.util.Set; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import jakarta.validation.executable.ExecutableValidator; + +/** + * 校验入口类。 + *

+ * 当调用的类或方法参数包含 {@link Validated} 注解时,会对该方法进行校验处理。 + *

+ * + * @author 易文渊 + * @since 2024-09-27 + */ +@Aspect(scope = Scope.GLOBAL) +@Component +public class ValidationHandler implements AutoCloseable { + private final ValidatorFactory validatorFactory; + private final Validator validator; + + public ValidationHandler() { + this.validatorFactory = Validation.byProvider(HibernateValidator.class) + .configure() + .messageInterpolator(new ParameterMessageInterpolator()) + .failFast(false) + .buildValidatorFactory(); + this.validator = validatorFactory.getValidator(); + } + + @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") + private void handle(JoinPoint joinPoint, Validated validated) { + // 检查方法参数是否包含被 javax.validation.Constraint 标注的校验注解 + if (hasJavaxConstraintAnnotations(joinPoint.getMethod().getParameters())) { + return; + } + ExecutableValidator execVal = this.validator.forExecutables(); + Set> result = execVal.validateParameters(joinPoint.getTarget(), + joinPoint.getMethod(), + joinPoint.getArgs(), + validated.value()); + if (!result.isEmpty()) { + throw new ConstraintViolationException(result); + } + } + + @PreDestroy + @Override + public void close() { + this.validatorFactory.close(); + } + + /** + * 检查方法参数是否包含被 javax.validation.Constraint 标注的校验注解 + * + * @param parameters 方法参数数组 + * @return 如果包含被 javax.validation.Constraint 标注的校验注解则返回 true,否则返回 false + */ + private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { + return Arrays.stream(parameters) + .flatMap(parameter -> Arrays.stream(parameter.getAnnotations())) + .anyMatch(this::isJavaxConstraintAnnotation); + } + + /** + * 检查注解是否被 javax.validation.Constraint 标注 + * + * @param annotation 要检查的注解 + * @return 如果被 javax.validation.Constraint 标注则返回 true,否则返回 false + */ + private boolean isJavaxConstraintAnnotation(Annotation annotation) { + Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); + return Arrays.stream(metaAnnotations) + .anyMatch(metaAnnotation -> { + String packageName = metaAnnotation.annotationType().getPackage().getName(); + String className = metaAnnotation.annotationType().getSimpleName(); + return "javax.validation".equals(packageName) && "Constraint".equals(className); + }); + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/resources/application.yaml b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/resources/application.yaml new file mode 100644 index 000000000..f9de2211d --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/resources/application.yaml @@ -0,0 +1,4 @@ +fit: + beans: + packages: + - 'modelengine.fitframework.validation' diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java new file mode 100644 index 000000000..d6cd04583 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java @@ -0,0 +1,90 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation; + +import modelengine.fit.http.client.HttpClassicClientResponse; +import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.test.annotation.MvcTest; +import modelengine.fitframework.test.domain.mvc.MockMvc; +import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; +import modelengine.fitframework.test.domain.mvc.request.MockRequestBuilder; +import modelengine.fitframework.validation.data.Company; +import modelengine.fitframework.validation.data.Employee; +import modelengine.fitframework.validation.data.ValidationDataController; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * {@link ValidationDataController} 的测试集。 + * + * @author 吕博文 + * @since 2024-08-15 + */ +@MvcTest(classes = {ValidationDataController.class}) +@DisplayName("测试 EvalDataController") +public class ValidationDataControllerTest { + @Fit + private MockMvc mockMvc; + + private HttpClassicClientResponse response; + + @AfterEach + void teardown() throws IOException { + if (this.response != null) { + this.response.close(); + } + } + + @Test + @DisplayName("合法 Company 对象校验") + void shouldOKWhenCreateValidCompany() { + Employee validEmployee = new Employee("John", 25); + Company validCompany = new Company(Collections.singletonList(validEmployee)); + MockRequestBuilder requestBuilder = + MockMvcRequestBuilders.post("/validation/company/default").jsonEntity(validCompany).responseType(Void.class); + this.response = this.mockMvc.perform(requestBuilder); + assertThat(this.response.statusCode()).isEqualTo(200); + } + + @Test + @DisplayName("不合法 Company 对象校验") + void shouldFailedWhenCreateInvalidCompany() { + Company invalidCompany = new Company(null); + MockRequestBuilder requestBuilder = + MockMvcRequestBuilders.post("/validation/company/default").jsonEntity(invalidCompany).responseType(Void.class); + this.response = this.mockMvc.perform(requestBuilder); + assertThat(this.response.statusCode()).isEqualTo(500); + } + + @Test + @DisplayName("自定义分组校验 Company 对象") + void shouldOKWhenCreateValidCompanyWithGroup() { + Employee validEmployee = new Employee("Jane", 30); + Company validCompany = new Company(Collections.singletonList(validEmployee)); + MockRequestBuilder requestBuilder = + MockMvcRequestBuilders.post("/validation/company/companyGroup").jsonEntity(validCompany).responseType(Void.class); + this.response = this.mockMvc.perform(requestBuilder); + assertThat(this.response.statusCode()).isEqualTo(200); + } + + @Test + @DisplayName("自定义分组校验 Company 对象") + void shouldFailedWhenCreateInvalidCompanyWithGroup() { + Employee invalidEmployee = new Employee("", 15); + Company invalidCompany = new Company(Collections.singletonList(invalidEmployee)); + MockRequestBuilder requestBuilder = + MockMvcRequestBuilders.post("/validation/company/companyGroup").jsonEntity(invalidCompany).responseType(Void.class); + this.response = this.mockMvc.perform(requestBuilder); + assertThat(this.response.statusCode()).isEqualTo(500); + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java new file mode 100644 index 000000000..a3bb6980a --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -0,0 +1,621 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.test.annotation.FitTestWithJunit; +import modelengine.fitframework.validation.data.Company; +import modelengine.fitframework.validation.data.Employee; +import modelengine.fitframework.validation.data.GroupValidateService; +import modelengine.fitframework.validation.data.ValidateService; +import modelengine.fitframework.validation.data.ValidationTestData; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jakarta.validation.ConstraintViolationException; + +/** + * {@link ValidationHandler} 的单元测试。 + * + * @author 易文渊 + * @since 2024-09-27 + */ +@DisplayName("测试注解校验功能") +@FitTestWithJunit(includeClasses = { + ValidateService.class, + ValidationHandler.class, + GroupValidateService.StudentValidateService.class, + GroupValidateService.TeacherValidateService.class, + GroupValidateService.AdvancedValidateService.class +}) +public class ValidationHandlerTest { + @Fit + private ValidateService validateService; + + @Test + @DisplayName("测试校验原始类型成功") + void givePrimitiveThenValidateOk() { + assertThatThrownBy(() -> this.validateService.foo0(-1)).isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是正数"); + } + + @Test + @DisplayName("测试校验结构体成功") + void giveClassThenValidateOk() { + assertThatThrownBy(() -> this.validateService.foo1(new Employee("sky", 17))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("年龄必须大于等于18"); + } + + @Test + @DisplayName("测试嵌套结构体成功") + void giveNestedClassThenValidateOk() { + assertThatThrownBy(() -> { + Employee employee = new Employee("sky", 17); + this.validateService.foo2(new Company(Collections.singletonList(employee))); + }).isInstanceOf(ConstraintViolationException.class).hasMessageContaining("年龄必须大于等于18"); + } + + @Test + @DisplayName("测试@NotNull注解") + void testNotNullValidation() { + assertThatThrownBy(() -> this.validateService.testNotNull(null)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("不能为null"); + } + + @Test + @DisplayName("测试@NotEmpty注解") + void testNotEmptyValidation() { + assertThatThrownBy(() -> this.validateService.testNotEmpty("")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("不能为空"); + } + + @Test + @DisplayName("测试@NotBlank注解") + void testNotBlankValidation() { + assertThatThrownBy(() -> this.validateService.testNotBlank(" ")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("不能为空"); + } + + @Test + @DisplayName("测试@Null注解") + void testNullValidation() { + assertThatThrownBy(() -> this.validateService.testNull("not null")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须为null"); + } + + @Test + @DisplayName("测试@Size注解-字符串") + void testSizeStringValidation() { + assertThatThrownBy(() -> this.validateService.testSize("a")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("个数必须在2和10之间"); + } + + @Test + @DisplayName("测试@Size注解-集合") + void testSizeListValidation() { + assertThatThrownBy(() -> this.validateService.testSizeList(Arrays.asList("1", "2", "3", "4"))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("个数必须在1和3之间"); + } + + @Test + @DisplayName("测试@Min注解") + void testMinValidation() { + assertThatThrownBy(() -> this.validateService.testMin(5)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("最小不能小于10"); + } + + @Test + @DisplayName("测试@Max注解") + void testMaxValidation() { + assertThatThrownBy(() -> this.validateService.testMax(150)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("最大不能超过100"); + } + + @Test + @DisplayName("测试@DecimalMin注解") + void testDecimalMinValidation() { + assertThatThrownBy(() -> this.validateService.testDecimalMin(new BigDecimal("5.0"))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须大于"); + } + + @Test + @DisplayName("测试@DecimalMax注解") + void testDecimalMaxValidation() { + assertThatThrownBy(() -> this.validateService.testDecimalMax(new BigDecimal("150.0"))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须小于"); + } + + @Test + @DisplayName("测试@Positive注解") + void testPositiveValidation() { + assertThatThrownBy(() -> this.validateService.testPositive(0)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是正数"); + } + + @Test + @DisplayName("测试@PositiveOrZero注解") + void testPositiveOrZeroValidation() { + assertThatThrownBy(() -> this.validateService.testPositiveOrZero(-1)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是正数或零"); + } + + @Test + @DisplayName("测试@Negative注解") + void testNegativeValidation() { + assertThatThrownBy(() -> this.validateService.testNegative(1)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是负数"); + } + + @Test + @DisplayName("测试@NegativeOrZero注解") + void testNegativeOrZeroValidation() { + assertThatThrownBy(() -> this.validateService.testNegativeOrZero(1)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是负数或零"); + } + + @Test + @DisplayName("测试@Digits注解") + void testDigitsValidation() { + assertThatThrownBy(() -> this.validateService.testDigits(new BigDecimal("1234.567"))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("数字的值超出了允许范围"); + } + + @Test + @DisplayName("测试@Past注解") + void testPastValidation() { + assertThatThrownBy(() -> this.validateService.testPast(LocalDate.now().plusDays(1))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要是一个过去的时间"); + } + + @Test + @DisplayName("测试@PastOrPresent注解") + void testPastOrPresentValidation() { + assertThatThrownBy(() -> this.validateService.testPastOrPresent(LocalDate.now().plusDays(1))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要是一个过去或现在的时间"); + } + + @Test + @DisplayName("测试@Future注解") + void testFutureValidation() { + assertThatThrownBy(() -> this.validateService.testFuture(LocalDate.now().minusDays(1))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要是一个将来的时间"); + } + + @Test + @DisplayName("测试@FutureOrPresent注解") + void testFutureOrPresentValidation() { + assertThatThrownBy(() -> this.validateService.testFutureOrPresent(LocalDate.now().minusDays(1))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要是一个将来或现在的时间"); + } + + @Test + @DisplayName("测试@Pattern注解") + void testPatternValidation() { + assertThatThrownBy(() -> this.validateService.testPattern("123")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要匹配正则表达式"); + } + + @Test + @DisplayName("测试@Email注解") + void testEmailValidation() { + assertThatThrownBy(() -> this.validateService.testEmail("invalid-email")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("不是一个合法的电子邮件地址"); + } + + @Test + @DisplayName("测试@AssertTrue注解") + void testAssertTrueValidation() { + assertThatThrownBy(() -> this.validateService.testAssertTrue(false)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("只能为true"); + } + + @Test + @DisplayName("测试@AssertFalse注解") + void testAssertFalseValidation() { + assertThatThrownBy(() -> this.validateService.testAssertFalse(true)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("只能为false"); + } + + @Test + @DisplayName("测试复杂对象校验") + void testComplexObjectValidation() { + ValidationTestData invalidData = new ValidationTestData(); + invalidData.setName(null); // 违反@NotNull + invalidData.setAge(200); // 违反@Max(150) + + assertThatThrownBy(() -> this.validateService.testValidObject(invalidData)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("名称不能为空"); + } + + @Test + @DisplayName("校验数据类,该数据类的 Constraint 字段会被校验,其余字段不会被校验") + public void givenFieldsWithConstraintAnnotationThenValidateHappened() { + Employee invalidEmployee = new Employee("", 150); // 空名字,年龄超限 + assertThatThrownBy(() -> validateService.validateEmployee(invalidEmployee)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("不能为空"); + } + + @Test + @DisplayName("校验方法参数,该方法的 Constraint 参数会被校验,其余参数不会被校验") + public void givenParametersWithConstraintAnnotationThenValidateHappened() { + assertThatThrownBy(() -> validateService.validateAge(-1)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是正数"); + } + + @Test + @DisplayName("校验多个参数") + public void givenMultipleParametersThenValidateHappened() { + assertThatThrownBy(() -> validateService.validateNameAndAge("", -1)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("校验数据类,只会校验与数据类的分组一致的字段分组") + public void givenFieldsThenSameGroupValidateHappened() { + ValidationTestData data = new ValidationTestData(); + data.setAge(300); // 违反高级分组的约束 + data.setName(""); // 违反默认分组约束 + + assertThatThrownBy(() -> validateService.validateAdvancedGroup(data)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("高级组年龄必须小于等于200"); + } + + @Test + @DisplayName("校验方法参数,分组约束测试") + public void givenParametersThenGroupValidateHappened() { + // 测试学生年龄验证 - 现在会抛出异常,因为使用了学生分组 + assertThatThrownBy(() -> validateService.validateStudentAge(25)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("范围要在7~20之内"); + } + + @Test + @DisplayName("校验方法参数,教师年龄验证测试") + public void givenParametersThenTeacherGroupValidateNotHappened() { + // 测试教师年龄验证 - 现在会抛出异常,因为使用了教师分组 + assertThatThrownBy(() -> validateService.validateTeacherAge(15)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("范围要在22~65之内"); + } + + @Test + @DisplayName("测试嵌套校验类 Company") + void shouldReturnMsgWhenValidateCompany() { + Employee invalidEmployee1 = new Employee("", 17); // 空名字,年龄不足 + Employee invalidEmployee2 = new Employee("John", 150); // 年龄超限 + Company company = new Company(Arrays.asList(invalidEmployee1, invalidEmployee2)); + + assertThatThrownBy(() -> validateService.validateCompany(company)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid List") + void shouldReturnMsgWhenValidateList() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee1 = new Employee("", 17); + Employee invalidEmployee2 = new Employee("Jane", 150); + List employees = Arrays.asList(validEmployee, invalidEmployee1, invalidEmployee2); + + assertThatThrownBy(() -> validateService.validateEmployeeList(employees)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid List>") + void shouldReturnMsgWhenValidateListInList() { + Employee validEmployee1 = new Employee("John", 25); + Employee validEmployee2 = new Employee("John", 25); + Employee invalidEmployee1 = new Employee("", 17); + Employee invalidEmployee2 = new Employee("Jane", 150); + + List employeeList1 = Arrays.asList(validEmployee1, invalidEmployee1); + List employeeList2 = Arrays.asList(validEmployee2, invalidEmployee2); + List> nestedList = Arrays.asList(employeeList1, employeeList2); + + assertThatThrownBy(() -> validateService.validateNestedEmployeeList(nestedList)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid Map") + void shouldReturnMsgWhenValidateMapSimple() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee1 = new Employee("", 17); + Employee invalidEmployee2 = new Employee("Jane", 150); + + Map employeeMap = new HashMap<>(); + employeeMap.put("1", validEmployee); + employeeMap.put("2", invalidEmployee1); + employeeMap.put("3", invalidEmployee2); + + assertThatThrownBy(() -> validateService.validateEmployeeMap(employeeMap)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid Map") + void shouldReturnMsgWhenValidateMapObj() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee = new Employee("", 17); + + ValidationTestData validData = new ValidationTestData(); + validData.setName("Test"); + validData.setAge(25); + + ValidationTestData invalidData = new ValidationTestData(); + invalidData.setName(""); + invalidData.setAge(-1); + + Map map = new HashMap<>(); + map.put(validEmployee, validData); + map.put(invalidEmployee, invalidData); + + assertThatThrownBy(() -> validateService.validateEmployeeDataMap(map)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid Map>") + void shouldReturnMsgWhenValidateMapInMap() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee = new Employee("", 17); + + ValidationTestData validData = new ValidationTestData(); + validData.setName("Test"); + validData.setAge(25); + + ValidationTestData invalidData = new ValidationTestData(); + invalidData.setName(""); + invalidData.setAge(-1); + + Map innerMap = new HashMap<>(); + innerMap.put("valid", validData); + innerMap.put("invalid", invalidData); + + Map> nestedMap = new HashMap<>(); + nestedMap.put(validEmployee, innerMap); + nestedMap.put(invalidEmployee, innerMap); + + assertThatThrownBy(() -> validateService.validateNestedEmployeeDataMap(nestedMap)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid List>") + void shouldReturnMsgWhenValidateMapInList() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee1 = new Employee("", 17); + Employee invalidEmployee2 = new Employee("Jane", 150); + + Map map1 = new HashMap<>(); + map1.put("valid", validEmployee); + map1.put("invalid1", invalidEmployee1); + + Map map2 = new HashMap<>(); + map2.put("valid", validEmployee); + map2.put("invalid2", invalidEmployee2); + + List> listOfMaps = Arrays.asList(map1, map2); + + assertThatThrownBy(() -> validateService.validateEmployeeMapList(listOfMaps)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid Map>") + void shouldReturnMsgWhenValidateListInMap() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee = new Employee("", 17); + + ValidationTestData validData = new ValidationTestData(); + validData.setName("Test"); + validData.setAge(25); + + ValidationTestData invalidData = new ValidationTestData(); + invalidData.setName(""); + invalidData.setAge(-1); + + List dataList1 = Arrays.asList(validData, invalidData); + List dataList2 = Arrays.asList(validData); + + Map> map = new HashMap<>(); + map.put(validEmployee, dataList1); + map.put(invalidEmployee, dataList2); + + assertThatThrownBy(() -> validateService.validateEmployeeDataListMap(map)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid List") + void shouldReturnMsgWhenValidateListComplex() { + Employee invalidEmployee = new Employee("", 17); + Company invalidCompany = new Company(Arrays.asList(invalidEmployee)); + List companies = Arrays.asList(invalidCompany); + + assertThatThrownBy(() -> validateService.validateCompanyList(companies)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试@NotNull注解-成功场景") + void testNotNullValidationSuccess() { + validateService.testNotNull("valid value"); + } + + @Test + @DisplayName("测试@Size注解-最小边界值") + void testSizeStringValidationMinBoundary() { + validateService.testSize("ab"); // 2个字符,最小边界 + } + + @Test + @DisplayName("测试@Size注解-最大边界值") + void testSizeStringValidationMaxBoundary() { + validateService.testSize("abcdefghij"); // 10个字符,最大边界 + } + + @Test + @DisplayName("测试@Min注解-边界值") + void testMinValidationBoundary() { + validateService.testMin(10); // 最小值边界 + } + + @Test + @DisplayName("测试@Max注解-边界值") + void testMaxValidationBoundary() { + validateService.testMax(100); // 最大值边界 + } + + @Test + @DisplayName("测试@Positive注解-边界值") + void testPositiveValidationBoundary() { + validateService.testPositive(1); // 最小正数 + } + + @Test + @DisplayName("测试@PositiveOrZero注解-零值") + void testPositiveOrZeroValidationZero() { + validateService.testPositiveOrZero(0); // 零值 + } + + @Test + @DisplayName("测试@Past注解-边界值") + void testPastValidationBoundary() { + validateService.testPast(LocalDate.now().minusDays(1)); // 昨天 + } + + @Test + @DisplayName("测试@Future注解-边界值") + void testFutureValidationBoundary() { + validateService.testFuture(LocalDate.now().plusDays(1)); // 明天 + } + + @Test + @DisplayName("测试有效的复杂对象") + void testValidComplexObject() { + ValidationTestData validData = new ValidationTestData(); + validData.setName("Test Name"); + validData.setAge(25); + validData.setDescription("Test Description"); + validData.setContent("Test Content"); + validData.setQuantity(10); + validData.setDiscount(new BigDecimal("-5.0")); + validData.setAgreed(true); + + validateService.testValidObject(validData); + } + + @Test + @DisplayName("测试多个验证失败") + void testMultipleValidationFailures() { + ValidationTestData invalidData = new ValidationTestData(); + invalidData.setName(""); // 违反@NotBlank + invalidData.setAge(-1); // 违反@Min(0) + invalidData.setQuantity(-10); // 违反@Positive + + assertThatThrownBy(() -> validateService.testValidObject(invalidData)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试混合原始类型和对象校验") + void testMixedPrimitiveAndObjectValidation() { + Employee invalidEmployee = new Employee("", 17); + assertThatThrownBy(() -> validateService.validateMixed(-1, invalidEmployee)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试空集合和null值混合") + void testEmptyCollectionAndNullMixed() { + assertThatThrownBy(() -> validateService.validateMixedCollections(null, Collections.emptyList())) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试@Range注解-最小值验证") + void testRangeMinValidation() { + assertThatThrownBy(() -> this.validateService.testRange(5)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要在10和100之间"); + } + + @Test + @DisplayName("测试@Range注解-最大值验证") + void testRangeMaxValidation() { + assertThatThrownBy(() -> this.validateService.testRange(150)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要在10和100之间"); + } + + @Test + @DisplayName("测试@Range注解-最小边界值") + void testRangeMinBoundary() { + validateService.testRange(10); // 最小边界值,应该通过 + } + + @Test + @DisplayName("测试@Range注解-最大边界值") + void testRangeMaxBoundary() { + validateService.testRange(100); // 最大边界值,应该通过 + } + + @Test + @DisplayName("测试@Range注解-中间值") + void testRangeValidValue() { + validateService.testRange(50); // 中间值,应该通过 + } + + @Test + @DisplayName("测试@Range注解-BigDecimal类型") + void testRangeBigDecimalValidation() { + assertThatThrownBy(() -> this.validateService.testRangeBigDecimal(new BigDecimal("5.5"))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要在10和100之间"); + } + +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java new file mode 100644 index 000000000..2bb304e7a --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + + + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import java.util.List; + +/** + * 公司实体类。 + * + * @author 易文渊 + * @since 2024-09-27 + */ +public class Company { + @NotNull + @Valid + private List employees; + + public Company() {} + + public Company(List employees) { + this.employees = employees; + } + + public List getEmployees() { + return employees; + } + + public void setEmployees(List employees) { + this.employees = employees; + } + + @Override + public String toString() { + return "Company{" + + "employees=" + employees + + '}'; + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java new file mode 100644 index 000000000..de383e2a5 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; + +/** + * 员工实体类。 + * + * @author 易文渊 + * @since 2024-09-27 + */ +public class Employee { + @NotBlank(message = "姓名不能为空") + private String name; + + @Min(value = 18, message = "年龄必须大于等于18") + private int age; + + public Employee() {} + + public Employee(String name, int age) { + this.name = name; + this.age = age; + } + + 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; + } + + @Override + public String toString() { + return "Employee{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java new file mode 100644 index 000000000..ad9f47931 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.log.Logger; +import modelengine.fitframework.validation.Validated; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; + +/** + * 表示测试用分组校验服务。 + * + * @author 易文渊 + * @since 2024-09-27 + */ +@Component +public class GroupValidateService { + private static final Logger LOG = Logger.get(GroupValidateService.class); + + // 学生年龄验证服务 + @Component + @Validated(ValidationTestData.StudentGroup.class) + public static class StudentValidateService { + public void validateStudentAge(@Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) + @Max(value = 20, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) int age) { + LOG.debug("Validating student age: {}", age); + } + } + + // 教师年龄验证服务 + @Component + @Validated(ValidationTestData.TeacherGroup.class) + public static class TeacherValidateService { + public void validateTeacherAge(@Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) + @Max(value = 65, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) int age) { + LOG.debug("Validating teacher age: {}", age); + } + } + + // 高级分组验证服务 + @Component + @Validated(ValidationTestData.AdvancedGroup.class) + public static class AdvancedValidateService { + public void validateAdvancedGroup(@Valid ValidationTestData data) { + LOG.debug("Validating advanced group data: {}", data); + } + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java new file mode 100644 index 000000000..ce53114a0 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -0,0 +1,202 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.log.Logger; +import modelengine.fitframework.validation.Validated; +import org.hibernate.validator.constraints.Range; + + + +import jakarta.validation.Valid; +import jakarta.validation.constraints.*; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +/** + * 表示测试用校验服务。 + * + * @author 易文渊 + * @since 2024-09-27 + */ +@Component +@Validated +public class ValidateService { + private static final Logger LOG = Logger.get(ValidateService.class); + + @Fit + private GroupValidateService.StudentValidateService studentValidateService; + + @Fit + private GroupValidateService.TeacherValidateService teacherValidateService; + + @Fit + private GroupValidateService.AdvancedValidateService advancedValidateService; + + /** + * 测试原始类型。 + * + * @param num 表示输入的 {@code int}。 + */ + public void foo0(@Positive(message = "必须是正数") int num) { + LOG.debug("{}", num); + } + + /** + * 测试结构体类型。 + * + * @param employee 表示输入的 {@code Employee}。 + */ + public void foo1(@Valid Employee employee) { + LOG.debug("{}", employee); + } + + /** + * 测试嵌套类型。 + * + * @param company 表示输入的 {@code Company}。 + */ + public void foo2(@Valid Company company) { + LOG.debug("{}", company); + } + + // 新增的校验注解测试方法 + public void testNotNull(@NotNull String value) {} + + public void testNotEmpty(@NotEmpty String value) {} + + public void testNotBlank(@NotBlank String value) {} + + public void testNull(@Null String value) {} + + public void testSize(@Size(min = 2, max = 10) String value) {} + + public void testSizeList(@Size(min = 1, max = 3) List value) {} + + public void testMin(@Min(10) int value) {} + + public void testMax(@Max(100) int value) {} + + public void testDecimalMin(@DecimalMin("10.5") BigDecimal value) {} + + public void testDecimalMax(@DecimalMax("100.5") BigDecimal value) {} + + public void testPositive(@Positive int value) {} + + public void testPositiveOrZero(@PositiveOrZero int value) {} + + public void testNegative(@Negative int value) {} + + public void testNegativeOrZero(@NegativeOrZero int value) {} + + public void testDigits(@Digits(integer = 3, fraction = 2) BigDecimal value) {} + + public void testPast(@Past LocalDate value) {} + + public void testPastOrPresent(@PastOrPresent LocalDate value) {} + + public void testFuture(@Future LocalDate value) {} + + public void testFutureOrPresent(@FutureOrPresent LocalDate value) {} + + public void testPattern(@Pattern(regexp = "^[a-zA-Z]+$") String value) {} + + public void testEmail(@Email String value) {} + + public void testAssertTrue(@AssertTrue boolean value) {} + + public void testAssertFalse(@AssertFalse boolean value) {} + + public void testValidObject(@Valid ValidationTestData data) {} + + // Range注解测试方法 + public void testRange(@Range(min = 10, max = 100, message = "需要在10和100之间") int value) {} + + public void testRangeBigDecimal(@Range(min = 10, max = 100, message = "需要在10和100之间") BigDecimal value) {} + + // 默认分组测试方法 + public void validateEmployee(@Valid Employee employee) { + LOG.debug("Validating employee: {}", employee); + } + + public void validateAge(@Positive(message = "必须是正数") int age) { + LOG.debug("Validating age: {}", age); + } + + public void validateNameAndAge(@NotBlank String name, @Positive int age) { + LOG.debug("Validating name: {} and age: {}", name, age); + } + + // 分组验证代理方法 + public void validateAdvancedGroup(ValidationTestData data) { + if (advancedValidateService != null) { + advancedValidateService.validateAdvancedGroup(data); + } + } + + public void validateStudentAge(int age) { + if (studentValidateService != null) { + studentValidateService.validateStudentAge(age); + } + } + + public void validateTeacherAge(int age) { + if (teacherValidateService != null) { + teacherValidateService.validateTeacherAge(age); + } + } + + // 嵌套测试方法 + public void validateCompany(@Valid Company company) { + LOG.debug("Validating company: {}", company); + } + + public void validateEmployeeList(List<@Valid Employee> employees) { + LOG.debug("Validating employee list: {}", employees); + } + + public void validateNestedEmployeeList(List> nestedList) { + LOG.debug("Validating nested employee list: {}", nestedList); + } + + public void validateEmployeeMap(@Valid Map employeeMap) { + LOG.debug("Validating employee map: {}", employeeMap); + } + + public void validateEmployeeDataMap(@Valid Map map) { + LOG.debug("Validating employee data map: {}", map); + } + + public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map> nestedMap) { + LOG.debug("Validating nested employee data map: {}", nestedMap); + } + + public void validateEmployeeMapList(List> listOfMaps) { + LOG.debug("Validating employee map list: {}", listOfMaps); + } + + public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { + LOG.debug("Validating employee data list map: {}", map); + } + + public void validateCompanyList(@Valid List companies) { + LOG.debug("Validating company list: {}", companies); + } + + // 混合场景测试方法 + public void validateMixed(@Positive int value, @Valid Employee employee) { + LOG.debug("Validating mixed primitive {} and object {}", value, employee); + } + + public void validateMixedCollections(@NotNull List list1, @NotEmpty List list2) { + LOG.debug("Validating mixed collections: {} and {}", list1, list2); + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java new file mode 100644 index 000000000..f8856f41b --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + +import modelengine.fit.http.annotation.PostMapping; +import modelengine.fit.http.annotation.RequestBody; +import modelengine.fit.http.annotation.RequestMapping; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.validation.Validated; + +import jakarta.validation.Valid; + +/** + * 表示评估注解验证数据接口集。 + * + * @author 吕博文 + * @since 2024-08-15 + */ +@Component +@Validated +@RequestMapping(path = "/validation", group = "评估注解验证数据接口") +public class ValidationDataController { + /** + * Company 类默认分组注解验证。 + * + * @param company 表示注解验证类 {@link Company}。 + */ + @PostMapping(path = "/company/default", description = "验证 Company 类默认分组注解") + public void validateCompanyDefaultGroup(@RequestBody @Valid Company company) {} + + /** + * Company 类特定分组注解验证。 + * + * @param company 表示注解验证类 {@link Company}。 + */ + @PostMapping(path = "/company/companyGroup", description = "验证 Company 类特定分组注解") + public void validateCompanyGroup(@RequestBody @Valid Company company) {} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java new file mode 100644 index 000000000..65bfae98f --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -0,0 +1,297 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + +import jakarta.validation.constraints.*; +import java.math.BigDecimal; +import java.time.LocalDate; + +/** + * 测试用的复杂验证数据类。 + * + * @since 2024-09-27 + */ +public class ValidationTestData { + + // 分组接口定义 + public interface BasicGroup {} + public interface AdvancedGroup {} + public interface StudentGroup {} + public interface TeacherGroup {} + + @NotBlank(message = "名称不能为空") + private String name; + + @Min(value = 0, message = "年龄必须大于等于0") + @Max(value = 150, message = "年龄必须小于等于150") + @Max(value = 200, message = "高级组年龄必须小于等于200", groups = AdvancedGroup.class) + private Integer age; + + @NotBlank(message = "描述不能为空") + private String description; + + @NotBlank(message = "内容不能为空白") + private String content; + + @Size(min = 2, max = 10, message = "标题长度必须在2-10之间") + private String title; + + @DecimalMin(value = "0.0", message = "价格必须大于等于0") + @DecimalMax(value = "999.99", message = "价格必须小于等于999.99") + private BigDecimal price; + + @Positive(message = "数量必须是正数") + private Integer quantity; + + @PositiveOrZero(message = "库存必须是正数或零") + private int stock; + + @Negative(message = "折扣必须是负数") + private BigDecimal discount; + + @NegativeOrZero(message = "债务必须是负数或零") + private int debt; + + @Digits(integer = 3, fraction = 2, message = "金额格式不正确") + private BigDecimal amount; + + @Past(message = "出生日期必须是过去时间") + private LocalDate birthDate; + + @PastOrPresent(message = "创建时间必须是过去或现在时间") + private LocalDate createDate; + + @Future(message = "到期时间必须是未来时间") + private LocalDate expireDate; + + @FutureOrPresent(message = "更新时间必须是未来或现在时间") + private LocalDate updateDate; + + @Pattern(regexp = "^[a-zA-Z]+$", message = "代码只能包含字母") + private String code; + + @Email(message = "邮箱格式不正确") + private String email; + + @AssertTrue(message = "必须同意条款") + private Boolean agreed; + + @AssertFalse(message = "必须取消订阅") + private boolean subscribed; + + // 构造函数 + public ValidationTestData() {} + + public ValidationTestData(String name, Integer age) { + this.name = name; + this.age = age; + } + + public ValidationTestData(String name, String description, String content, String title, + int age, BigDecimal price, int quantity, int stock, BigDecimal discount, + int debt, BigDecimal amount, LocalDate birthDate, LocalDate createDate, + LocalDate expireDate, LocalDate updateDate, String code, String email, + Boolean agreed, boolean subscribed) { + this.name = name; + this.description = description; + this.content = content; + this.title = title; + this.age = age; + this.price = price; + this.quantity = quantity; + this.stock = stock; + this.discount = discount; + this.debt = debt; + this.amount = amount; + this.birthDate = birthDate; + this.createDate = createDate; + this.expireDate = expireDate; + this.updateDate = updateDate; + this.code = code; + this.email = email; + this.agreed = agreed; + this.subscribed = subscribed; + } + + // Getters and Setters + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public int getStock() { + return stock; + } + + public void setStock(int stock) { + this.stock = stock; + } + + public BigDecimal getDiscount() { + return discount; + } + + public void setDiscount(BigDecimal discount) { + this.discount = discount; + } + + public int getDebt() { + return debt; + } + + public void setDebt(int debt) { + this.debt = debt; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public LocalDate getBirthDate() { + return birthDate; + } + + public void setBirthDate(LocalDate birthDate) { + this.birthDate = birthDate; + } + + public LocalDate getCreateDate() { + return createDate; + } + + public void setCreateDate(LocalDate createDate) { + this.createDate = createDate; + } + + public LocalDate getExpireDate() { + return expireDate; + } + + public void setExpireDate(LocalDate expireDate) { + this.expireDate = expireDate; + } + + public LocalDate getUpdateDate() { + return updateDate; + } + + public void setUpdateDate(LocalDate updateDate) { + this.updateDate = updateDate; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Boolean getAgreed() { + return agreed; + } + + public void setAgreed(Boolean agreed) { + this.agreed = agreed; + } + + public boolean isSubscribed() { + return subscribed; + } + + public void setSubscribed(boolean subscribed) { + this.subscribed = subscribed; + } + + @Override + public String toString() { + return "ValidationTestData{" + + "name='" + name + '\'' + + ", age=" + age + + ", description='" + description + '\'' + + ", content='" + content + '\'' + + ", title='" + title + '\'' + + ", price=" + price + + ", quantity=" + quantity + + ", stock=" + stock + + ", discount=" + discount + + ", debt=" + debt + + ", amount=" + amount + + ", birthDate=" + birthDate + + ", createDate=" + createDate + + ", expireDate=" + expireDate + + ", updateDate=" + updateDate + + ", code='" + code + '\'' + + ", email='" + email + '\'' + + ", agreed=" + agreed + + ", subscribed=" + subscribed + + '}'; + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml new file mode 100644 index 000000000..ca66ddcb4 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml @@ -0,0 +1,114 @@ + + + 4.0.0 + + + org.fitframework.plugin + fit-plugin-parent + 3.6.0-SNAPSHOT + + + fit-hibernate-validation + + FIT Hibernate Validation + FIT Framework Hibernate Validation module provides Validation for args. + + https://github.com/ModelEngine-Group/fit-framework + + + + 6.2.5.Final + + + + + + + org.fitframework + fit-api + + + + + org.hibernate.validator + hibernate-validator + ${hibernate.version} + + + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-core + test + + + org.assertj + assertj-core + test + + + org.fitframework + fit-test-framework + test + + + com.h2database + h2 + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + + copy-dependencies + + + ../../../../../../build/shared/ + jakarta.validation + + + + + + org.fitframework + fit-build-maven-plugin + + system + 1 + + + + org.apache.maven.plugins + maven-antrun-plugin + + + package + + + + + + + run + + + + + + + + diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java new file mode 100644 index 000000000..79eb44f08 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -0,0 +1,105 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation; + +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Scope; +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.aop.annotation.Aspect; +import modelengine.fitframework.aop.annotation.Before; +import modelengine.fitframework.ioc.annotation.PreDestroy; + +import org.hibernate.validator.HibernateValidator; +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Parameter; +import java.util.Arrays; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import javax.validation.executable.ExecutableValidator; + +/** + * 校验入口类。 + *

+ * 当调用的类或方法参数包含 {@link Validated} 注解时,会对该方法进行校验处理。 + *

+ * + * @author 易文渊 + * @since 2024-09-27 + */ +@Aspect(scope = Scope.GLOBAL) +@Component +public class ValidationHandler implements AutoCloseable { + private final ValidatorFactory validatorFactory; + private final Validator validator; + + ValidationHandler() { + this.validatorFactory = Validation.byProvider(HibernateValidator.class) + .configure() + .messageInterpolator(new ParameterMessageInterpolator()) + .failFast(false) + .buildValidatorFactory(); + this.validator = validatorFactory.getValidator(); + } + + @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") + private void handle(JoinPoint joinPoint, Validated validated) { + // 检查方法参数是否包含被 jakarta.validation.Constraint 标注的校验注解 + if (hasJakartaConstraintAnnotations(joinPoint.getMethod().getParameters())) { + return; + } + + ExecutableValidator execVal = this.validator.forExecutables(); + Set> result = execVal.validateParameters(joinPoint.getTarget(), + joinPoint.getMethod(), + joinPoint.getArgs(), + validated.value()); + if (!result.isEmpty()) { + throw new ConstraintViolationException(result); + } + } + + @PreDestroy + @Override + public void close() { + this.validatorFactory.close(); + } + + /** + * 检查方法参数是否包含被 jakarta.validation.Constraint 标注的校验注解 + * + * @param parameters 方法参数数组 + * @return 如果包含被 jakarta.validation.Constraint 标注的校验注解则返回 true,否则返回 false + */ + private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { + return Arrays.stream(parameters) + .flatMap(parameter -> Arrays.stream(parameter.getAnnotations())) + .anyMatch(this::isJakartaConstraintAnnotation); + } + + /** + * 检查注解是否被 jakarta.validation.Constraint 标注 + * + * @param annotation 要检查的注解 + * @return 如果被 jakarta.validation.Constraint 标注则返回 true,否则返回 false + */ + private boolean isJakartaConstraintAnnotation(Annotation annotation) { + Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); + return Arrays.stream(metaAnnotations) + .anyMatch(metaAnnotation -> { + String packageName = metaAnnotation.annotationType().getPackage().getName(); + String className = metaAnnotation.annotationType().getSimpleName(); + return "jakarta.validation".equals(packageName) && "Constraint".equals(className); + }); + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/resources/application.yaml b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/resources/application.yaml new file mode 100644 index 000000000..f9de2211d --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/resources/application.yaml @@ -0,0 +1,4 @@ +fit: + beans: + packages: + - 'modelengine.fitframework.validation' diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java new file mode 100644 index 000000000..d9b94b4b4 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java @@ -0,0 +1,91 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation; + +import modelengine.fit.http.client.HttpClassicClientResponse; +import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.test.annotation.MvcTest; +import modelengine.fitframework.test.domain.mvc.MockMvc; +import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; +import modelengine.fitframework.test.domain.mvc.request.MockRequestBuilder; +import modelengine.fitframework.validation.data.Company; +import modelengine.fitframework.validation.data.Employee; +import modelengine.fitframework.validation.data.ValidationDataController; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * {@link ValidationDataController} 的测试集。 + * + * @author 吕博文 + * @since 2024-08-15 + */ +@MvcTest(classes = {ValidationDataController.class}) +@DisplayName("测试 EvalDataController") +public class ValidationDataControllerTest { + @Fit + private MockMvc mockMvc; + + private HttpClassicClientResponse response; + + @AfterEach + void teardown() throws IOException { + if (this.response != null) { + this.response.close(); + } + } + + @Test + @DisplayName("合法 Company 对象校验") + void shouldOKWhenCreateValidCompany() { + Employee validEmployee = new Employee("John", 25); + Company validCompany = new Company(Collections.singletonList(validEmployee)); + MockRequestBuilder requestBuilder = + MockMvcRequestBuilders.post("/validation/company/default").jsonEntity(validCompany).responseType(Void.class); + this.response = this.mockMvc.perform(requestBuilder); + assertThat(this.response.statusCode()).isEqualTo(200); + } + + @Test + @DisplayName("不合法 Company 对象校验") + void shouldFailedWhenCreateInvalidCompany() { + Company invalidCompany = new Company(null); + MockRequestBuilder requestBuilder = + MockMvcRequestBuilders.post("/validation/company/default").jsonEntity(invalidCompany).responseType(Void.class); + this.response = this.mockMvc.perform(requestBuilder); + assertThat(this.response.statusCode()).isEqualTo(500); + } + + @Test + @DisplayName("自定义分组校验 Company 对象") + void shouldOKWhenCreateValidCompanyWithGroup() { + Employee validEmployee = new Employee("Jane", 30); + Company validCompany = new Company(Collections.singletonList(validEmployee)); + MockRequestBuilder requestBuilder = + MockMvcRequestBuilders.post("/validation/company/companyGroup").jsonEntity(validCompany).responseType(Void.class); + this.response = this.mockMvc.perform(requestBuilder); + assertThat(this.response.statusCode()).isEqualTo(200); + } + + @Test + @DisplayName("自定义分组校验 Company 对象") + void shouldFailedWhenCreateInvalidCompanyWithGroup() { + Employee invalidEmployee = new Employee("", 15); + Company invalidCompany = new Company(Collections.singletonList(invalidEmployee)); + MockRequestBuilder requestBuilder = + MockMvcRequestBuilders.post("/validation/company/companyGroup").jsonEntity(invalidCompany).responseType(Void.class); + this.response = this.mockMvc.perform(requestBuilder); + assertThat(this.response.statusCode()).isEqualTo(500); + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java new file mode 100644 index 000000000..50378b0e4 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -0,0 +1,620 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.test.annotation.FitTestWithJunit; +import modelengine.fitframework.validation.data.Company; +import modelengine.fitframework.validation.data.Employee; +import modelengine.fitframework.validation.data.GroupValidateService; +import modelengine.fitframework.validation.data.ValidateService; +import modelengine.fitframework.validation.data.ValidationTestData; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.validation.ConstraintViolationException; + +/** + * {@link ValidationHandler} 的单元测试。 + * + * @author 易文渊 + * @since 2024-09-27 + */ +@DisplayName("测试注解校验功能") +@FitTestWithJunit(includeClasses = { + ValidateService.class, + ValidationHandler.class, + GroupValidateService.StudentValidateService.class, + GroupValidateService.TeacherValidateService.class, + GroupValidateService.AdvancedValidateService.class +}) +public class ValidationHandlerTest { + @Fit + private ValidateService validateService; + + @Test + @DisplayName("测试校验原始类型成功") + void givePrimitiveThenValidateOk() { + assertThatThrownBy(() -> this.validateService.foo0(-1)).isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是正数"); + } + + @Test + @DisplayName("测试校验结构体成功") + void giveClassThenValidateOk() { + assertThatThrownBy(() -> this.validateService.foo1(new Employee("sky", 17))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("年龄必须大于等于18"); + } + + @Test + @DisplayName("测试嵌套结构体成功") + void giveNestedClassThenValidateOk() { + assertThatThrownBy(() -> { + Employee employee = new Employee("sky", 17); + this.validateService.foo2(new Company(Collections.singletonList(employee))); + }).isInstanceOf(ConstraintViolationException.class).hasMessageContaining("年龄必须大于等于18"); + } + + @Test + @DisplayName("测试@NotNull注解") + void testNotNullValidation() { + assertThatThrownBy(() -> this.validateService.testNotNull(null)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("不能为null"); + } + + @Test + @DisplayName("测试@NotEmpty注解") + void testNotEmptyValidation() { + assertThatThrownBy(() -> this.validateService.testNotEmpty("")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("不能为空"); + } + + @Test + @DisplayName("测试@NotBlank注解") + void testNotBlankValidation() { + assertThatThrownBy(() -> this.validateService.testNotBlank(" ")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("不能为空"); + } + + @Test + @DisplayName("测试@Null注解") + void testNullValidation() { + assertThatThrownBy(() -> this.validateService.testNull("not null")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须为null"); + } + + @Test + @DisplayName("测试@Size注解-字符串") + void testSizeStringValidation() { + assertThatThrownBy(() -> this.validateService.testSize("a")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("个数必须在2和10之间"); + } + + @Test + @DisplayName("测试@Size注解-集合") + void testSizeListValidation() { + assertThatThrownBy(() -> this.validateService.testSizeList(Arrays.asList("1", "2", "3", "4"))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("个数必须在1和3之间"); + } + + @Test + @DisplayName("测试@Min注解") + void testMinValidation() { + assertThatThrownBy(() -> this.validateService.testMin(5)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("最小不能小于10"); + } + + @Test + @DisplayName("测试@Max注解") + void testMaxValidation() { + assertThatThrownBy(() -> this.validateService.testMax(150)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("最大不能超过100"); + } + + @Test + @DisplayName("测试@DecimalMin注解") + void testDecimalMinValidation() { + assertThatThrownBy(() -> this.validateService.testDecimalMin(new BigDecimal("5.0"))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须大于"); + } + + @Test + @DisplayName("测试@DecimalMax注解") + void testDecimalMaxValidation() { + assertThatThrownBy(() -> this.validateService.testDecimalMax(new BigDecimal("150.0"))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须小于"); + } + + @Test + @DisplayName("测试@Positive注解") + void testPositiveValidation() { + assertThatThrownBy(() -> this.validateService.testPositive(0)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是正数"); + } + + @Test + @DisplayName("测试@PositiveOrZero注解") + void testPositiveOrZeroValidation() { + assertThatThrownBy(() -> this.validateService.testPositiveOrZero(-1)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是正数或零"); + } + + @Test + @DisplayName("测试@Negative注解") + void testNegativeValidation() { + assertThatThrownBy(() -> this.validateService.testNegative(1)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是负数"); + } + + @Test + @DisplayName("测试@NegativeOrZero注解") + void testNegativeOrZeroValidation() { + assertThatThrownBy(() -> this.validateService.testNegativeOrZero(1)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是负数或零"); + } + + @Test + @DisplayName("测试@Digits注解") + void testDigitsValidation() { + assertThatThrownBy(() -> this.validateService.testDigits(new BigDecimal("1234.567"))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("数字的值超出了允许范围"); + } + + @Test + @DisplayName("测试@Past注解") + void testPastValidation() { + assertThatThrownBy(() -> this.validateService.testPast(LocalDate.now().plusDays(1))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要是一个过去的时间"); + } + + @Test + @DisplayName("测试@PastOrPresent注解") + void testPastOrPresentValidation() { + assertThatThrownBy(() -> this.validateService.testPastOrPresent(LocalDate.now().plusDays(1))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要是一个过去或现在的时间"); + } + + @Test + @DisplayName("测试@Future注解") + void testFutureValidation() { + assertThatThrownBy(() -> this.validateService.testFuture(LocalDate.now().minusDays(1))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要是一个将来的时间"); + } + + @Test + @DisplayName("测试@FutureOrPresent注解") + void testFutureOrPresentValidation() { + assertThatThrownBy(() -> this.validateService.testFutureOrPresent(LocalDate.now().minusDays(1))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要是一个将来或现在的时间"); + } + + @Test + @DisplayName("测试@Pattern注解") + void testPatternValidation() { + assertThatThrownBy(() -> this.validateService.testPattern("123")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要匹配正则表达式"); + } + + @Test + @DisplayName("测试@Email注解") + void testEmailValidation() { + assertThatThrownBy(() -> this.validateService.testEmail("invalid-email")) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("不是一个合法的电子邮件地址"); + } + + @Test + @DisplayName("测试@AssertTrue注解") + void testAssertTrueValidation() { + assertThatThrownBy(() -> this.validateService.testAssertTrue(false)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("只能为true"); + } + + @Test + @DisplayName("测试@AssertFalse注解") + void testAssertFalseValidation() { + assertThatThrownBy(() -> this.validateService.testAssertFalse(true)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("只能为false"); + } + + @Test + @DisplayName("测试复杂对象校验") + void testComplexObjectValidation() { + ValidationTestData invalidData = new ValidationTestData(); + invalidData.setName(null); // 违反@NotNull + invalidData.setAge(200); // 违反@Max(150) + + assertThatThrownBy(() -> this.validateService.testValidObject(invalidData)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("名称不能为空"); + } + + @Test + @DisplayName("校验数据类,该数据类的 Constraint 字段会被校验,其余字段不会被校验") + public void givenFieldsWithConstraintAnnotationThenValidateHappened() { + Employee invalidEmployee = new Employee("", 150); // 空名字,年龄超限 + assertThatThrownBy(() -> validateService.validateEmployee(invalidEmployee)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("不能为空"); + } + + @Test + @DisplayName("校验方法参数,该方法的 Constraint 参数会被校验,其余参数不会被校验") + public void givenParametersWithConstraintAnnotationThenValidateHappened() { + assertThatThrownBy(() -> validateService.validateAge(-1)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("必须是正数"); + } + + @Test + @DisplayName("校验多个参数") + public void givenMultipleParametersThenValidateHappened() { + assertThatThrownBy(() -> validateService.validateNameAndAge("", -1)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("校验数据类,只会校验与数据类的分组一致的字段分组") + public void givenFieldsThenSameGroupValidateHappened() { + ValidationTestData data = new ValidationTestData(); + data.setAge(300); // 违反高级分组的约束 + data.setName(""); // 违反默认分组约束 + + assertThatThrownBy(() -> validateService.validateAdvancedGroup(data)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("高级组年龄必须小于等于200"); + } + + @Test + @DisplayName("校验方法参数,分组约束测试") + public void givenParametersThenGroupValidateHappened() { + // 测试学生年龄验证 - 现在会抛出异常,因为使用了学生分组 + assertThatThrownBy(() -> validateService.validateStudentAge(25)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("范围要在7~20之内"); + } + + @Test + @DisplayName("校验方法参数,教师年龄验证测试") + public void givenParametersThenTeacherGroupValidateNotHappened() { + // 测试教师年龄验证 - 现在会抛出异常,因为使用了教师分组 + assertThatThrownBy(() -> validateService.validateTeacherAge(15)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("范围要在22~65之内"); + } + + @Test + @DisplayName("测试嵌套校验类 Company") + void shouldReturnMsgWhenValidateCompany() { + Employee invalidEmployee1 = new Employee("", 17); // 空名字,年龄不足 + Employee invalidEmployee2 = new Employee("John", 150); // 年龄超限 + Company company = new Company(Arrays.asList(invalidEmployee1, invalidEmployee2)); + + assertThatThrownBy(() -> validateService.validateCompany(company)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid List") + void shouldReturnMsgWhenValidateList() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee1 = new Employee("", 17); + Employee invalidEmployee2 = new Employee("Jane", 150); + List employees = Arrays.asList(validEmployee, invalidEmployee1, invalidEmployee2); + + assertThatThrownBy(() -> validateService.validateEmployeeList(employees)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid List>") + void shouldReturnMsgWhenValidateListInList() { + Employee validEmployee1 = new Employee("John", 25); + Employee validEmployee2 = new Employee("John", 25); + Employee invalidEmployee1 = new Employee("", 17); + Employee invalidEmployee2 = new Employee("Jane", 150); + + List employeeList1 = Arrays.asList(validEmployee1, invalidEmployee1); + List employeeList2 = Arrays.asList(validEmployee2, invalidEmployee2); + List> nestedList = Arrays.asList(employeeList1, employeeList2); + + assertThatThrownBy(() -> validateService.validateNestedEmployeeList(nestedList)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid Map") + void shouldReturnMsgWhenValidateMapSimple() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee1 = new Employee("", 17); + Employee invalidEmployee2 = new Employee("Jane", 150); + + Map employeeMap = new HashMap<>(); + employeeMap.put("1", validEmployee); + employeeMap.put("2", invalidEmployee1); + employeeMap.put("3", invalidEmployee2); + + assertThatThrownBy(() -> validateService.validateEmployeeMap(employeeMap)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid Map") + void shouldReturnMsgWhenValidateMapObj() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee = new Employee("", 17); + + ValidationTestData validData = new ValidationTestData(); + validData.setName("Test"); + validData.setAge(25); + + ValidationTestData invalidData = new ValidationTestData(); + invalidData.setName(""); + invalidData.setAge(-1); + + Map map = new HashMap<>(); + map.put(validEmployee, validData); + map.put(invalidEmployee, invalidData); + + assertThatThrownBy(() -> validateService.validateEmployeeDataMap(map)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid Map>") + void shouldReturnMsgWhenValidateMapInMap() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee = new Employee("", 17); + + ValidationTestData validData = new ValidationTestData(); + validData.setName("Test"); + validData.setAge(25); + + ValidationTestData invalidData = new ValidationTestData(); + invalidData.setName(""); + invalidData.setAge(-1); + + Map innerMap = new HashMap<>(); + innerMap.put("valid", validData); + innerMap.put("invalid", invalidData); + + Map> nestedMap = new HashMap<>(); + nestedMap.put(validEmployee, innerMap); + nestedMap.put(invalidEmployee, innerMap); + + assertThatThrownBy(() -> validateService.validateNestedEmployeeDataMap(nestedMap)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid List>") + void shouldReturnMsgWhenValidateMapInList() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee1 = new Employee("", 17); + Employee invalidEmployee2 = new Employee("Jane", 150); + + Map map1 = new HashMap<>(); + map1.put("valid", validEmployee); + map1.put("invalid1", invalidEmployee1); + + Map map2 = new HashMap<>(); + map2.put("valid", validEmployee); + map2.put("invalid2", invalidEmployee2); + + List> listOfMaps = Arrays.asList(map1, map2); + + assertThatThrownBy(() -> validateService.validateEmployeeMapList(listOfMaps)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid Map>") + void shouldReturnMsgWhenValidateListInMap() { + Employee validEmployee = new Employee("John", 25); + Employee invalidEmployee = new Employee("", 17); + + ValidationTestData validData = new ValidationTestData(); + validData.setName("Test"); + validData.setAge(25); + + ValidationTestData invalidData = new ValidationTestData(); + invalidData.setName(""); + invalidData.setAge(-1); + + List dataList1 = Arrays.asList(validData, invalidData); + List dataList2 = Arrays.asList(validData); + + Map> map = new HashMap<>(); + map.put(validEmployee, dataList1); + map.put(invalidEmployee, dataList2); + + assertThatThrownBy(() -> validateService.validateEmployeeDataListMap(map)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试 @Valid List") + void shouldReturnMsgWhenValidateListComplex() { + Employee invalidEmployee = new Employee("", 17); + Company invalidCompany = new Company(Arrays.asList(invalidEmployee)); + List companies = Arrays.asList(invalidCompany); + + assertThatThrownBy(() -> validateService.validateCompanyList(companies)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试@NotNull注解-成功场景") + void testNotNullValidationSuccess() { + validateService.testNotNull("valid value"); + } + + @Test + @DisplayName("测试@Size注解-最小边界值") + void testSizeStringValidationMinBoundary() { + validateService.testSize("ab"); // 2个字符,最小边界 + } + + @Test + @DisplayName("测试@Size注解-最大边界值") + void testSizeStringValidationMaxBoundary() { + validateService.testSize("abcdefghij"); // 10个字符,最大边界 + } + + @Test + @DisplayName("测试@Min注解-边界值") + void testMinValidationBoundary() { + validateService.testMin(10); // 最小值边界 + } + + @Test + @DisplayName("测试@Max注解-边界值") + void testMaxValidationBoundary() { + validateService.testMax(100); // 最大值边界 + } + + @Test + @DisplayName("测试@Positive注解-边界值") + void testPositiveValidationBoundary() { + validateService.testPositive(1); // 最小正数 + } + + @Test + @DisplayName("测试@PositiveOrZero注解-零值") + void testPositiveOrZeroValidationZero() { + validateService.testPositiveOrZero(0); // 零值 + } + + @Test + @DisplayName("测试@Past注解-边界值") + void testPastValidationBoundary() { + validateService.testPast(LocalDate.now().minusDays(1)); // 昨天 + } + + @Test + @DisplayName("测试@Future注解-边界值") + void testFutureValidationBoundary() { + validateService.testFuture(LocalDate.now().plusDays(1)); // 明天 + } + + @Test + @DisplayName("测试有效的复杂对象") + void testValidComplexObject() { + ValidationTestData validData = new ValidationTestData(); + validData.setName("Test Name"); + validData.setAge(25); + validData.setDescription("Test Description"); + validData.setContent("Test Content"); + validData.setQuantity(10); + validData.setDiscount(new BigDecimal("-5.0")); + validData.setAgreed(true); + + validateService.testValidObject(validData); + } + + @Test + @DisplayName("测试多个验证失败") + void testMultipleValidationFailures() { + ValidationTestData invalidData = new ValidationTestData(); + invalidData.setName(""); // 违反@NotBlank + invalidData.setAge(-1); // 违反@Min(0) + invalidData.setQuantity(-10); // 违反@Positive + + assertThatThrownBy(() -> validateService.testValidObject(invalidData)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试混合原始类型和对象校验") + void testMixedPrimitiveAndObjectValidation() { + Employee invalidEmployee = new Employee("", 17); + assertThatThrownBy(() -> validateService.validateMixed(-1, invalidEmployee)) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试空集合和null值混合") + void testEmptyCollectionAndNullMixed() { + assertThatThrownBy(() -> validateService.validateMixedCollections(null, Collections.emptyList())) + .isInstanceOf(ConstraintViolationException.class); + } + + @Test + @DisplayName("测试@Range注解-最小值验证") + void testRangeMinValidation() { + assertThatThrownBy(() -> this.validateService.testRange(5)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要在10和100之间"); + } + + @Test + @DisplayName("测试@Range注解-最大值验证") + void testRangeMaxValidation() { + assertThatThrownBy(() -> this.validateService.testRange(150)) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要在10和100之间"); + } + + @Test + @DisplayName("测试@Range注解-最小边界值") + void testRangeMinBoundary() { + validateService.testRange(10); // 最小边界值,应该通过 + } + + @Test + @DisplayName("测试@Range注解-最大边界值") + void testRangeMaxBoundary() { + validateService.testRange(100); // 最大边界值,应该通过 + } + + @Test + @DisplayName("测试@Range注解-中间值") + void testRangeValidValue() { + validateService.testRange(50); // 中间值,应该通过 + } + + @Test + @DisplayName("测试@Range注解-BigDecimal类型") + void testRangeBigDecimalValidation() { + assertThatThrownBy(() -> this.validateService.testRangeBigDecimal(new BigDecimal("5.5"))) + .isInstanceOf(ConstraintViolationException.class) + .hasMessageContaining("需要在10和100之间"); + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Company.java new file mode 100644 index 000000000..9cfd8fab4 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + + + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 公司实体类。 + * + * @author 易文渊 + * @since 2024-09-27 + */ +public class Company { + @NotNull + @Valid + private List employees; + + public Company() {} + + public Company(List employees) { + this.employees = employees; + } + + public List getEmployees() { + return employees; + } + + public void setEmployees(List employees) { + this.employees = employees; + } + + @Override + public String toString() { + return "Company{" + + "employees=" + employees + + '}'; + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Employee.java new file mode 100644 index 000000000..455ebe903 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; + +/** + * 员工实体类。 + * + * @author 易文渊 + * @since 2024-09-27 + */ +public class Employee { + @NotBlank(message = "姓名不能为空") + private String name; + + @Min(value = 18, message = "年龄必须大于等于18") + private int age; + + public Employee() {} + + public Employee(String name, int age) { + this.name = name; + this.age = age; + } + + 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; + } + + @Override + public String toString() { + return "Employee{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java new file mode 100644 index 000000000..0254ec22c --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.log.Logger; +import modelengine.fitframework.validation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + +/** + * 表示测试用分组校验服务。 + * + * @author 易文渊 + * @since 2024-09-27 + */ +@Component +public class GroupValidateService { + private static final Logger LOG = Logger.get(GroupValidateService.class); + + // 学生年龄验证服务 + @Component + @Validated(ValidationTestData.StudentGroup.class) + public static class StudentValidateService { + public void validateStudentAge(@Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) + @Max(value = 20, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) int age) { + LOG.debug("Validating student age: {}", age); + } + } + + // 教师年龄验证服务 + @Component + @Validated(ValidationTestData.TeacherGroup.class) + public static class TeacherValidateService { + public void validateTeacherAge(@Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) + @Max(value = 65, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) int age) { + LOG.debug("Validating teacher age: {}", age); + } + } + + // 高级分组验证服务 + @Component + @Validated(ValidationTestData.AdvancedGroup.class) + public static class AdvancedValidateService { + public void validateAdvancedGroup(@Valid ValidationTestData data) { + LOG.debug("Validating advanced group data: {}", data); + } + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidateService.java new file mode 100644 index 000000000..dfe8f1181 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -0,0 +1,202 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.log.Logger; +import modelengine.fitframework.validation.Validated; +import org.hibernate.validator.constraints.Range; + + + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +/** + * 表示测试用校验服务。 + * + * @author 易文渊 + * @since 2024-09-27 + */ +@Component +@Validated +public class ValidateService { + private static final Logger LOG = Logger.get(ValidateService.class); + + @Fit + private GroupValidateService.StudentValidateService studentValidateService; + + @Fit + private GroupValidateService.TeacherValidateService teacherValidateService; + + @Fit + private GroupValidateService.AdvancedValidateService advancedValidateService; + + /** + * 测试原始类型。 + * + * @param num 表示输入的 {@code int}。 + */ + public void foo0(@Positive(message = "必须是正数") int num) { + LOG.debug("{}", num); + } + + /** + * 测试结构体类型。 + * + * @param employee 表示输入的 {@code Employee}。 + */ + public void foo1(@Valid Employee employee) { + LOG.debug("{}", employee); + } + + /** + * 测试嵌套类型。 + * + * @param company 表示输入的 {@code Company}。 + */ + public void foo2(@Valid Company company) { + LOG.debug("{}", company); + } + + // 新增的校验注解测试方法 + public void testNotNull(@NotNull String value) {} + + public void testNotEmpty(@NotEmpty String value) {} + + public void testNotBlank(@NotBlank String value) {} + + public void testNull(@Null String value) {} + + public void testSize(@Size(min = 2, max = 10) String value) {} + + public void testSizeList(@Size(min = 1, max = 3) List value) {} + + public void testMin(@Min(10) int value) {} + + public void testMax(@Max(100) int value) {} + + public void testDecimalMin(@DecimalMin("10.5") BigDecimal value) {} + + public void testDecimalMax(@DecimalMax("100.5") BigDecimal value) {} + + public void testPositive(@Positive int value) {} + + public void testPositiveOrZero(@PositiveOrZero int value) {} + + public void testNegative(@Negative int value) {} + + public void testNegativeOrZero(@NegativeOrZero int value) {} + + public void testDigits(@Digits(integer = 3, fraction = 2) BigDecimal value) {} + + public void testPast(@Past LocalDate value) {} + + public void testPastOrPresent(@PastOrPresent LocalDate value) {} + + public void testFuture(@Future LocalDate value) {} + + public void testFutureOrPresent(@FutureOrPresent LocalDate value) {} + + public void testPattern(@Pattern(regexp = "^[a-zA-Z]+$") String value) {} + + public void testEmail(@Email String value) {} + + public void testAssertTrue(@AssertTrue boolean value) {} + + public void testAssertFalse(@AssertFalse boolean value) {} + + public void testValidObject(@Valid ValidationTestData data) {} + + // Range注解测试方法 + public void testRange(@Range(min = 10, max = 100, message = "需要在10和100之间") int value) {} + + public void testRangeBigDecimal(@Range(min = 10, max = 100, message = "需要在10和100之间") BigDecimal value) {} + + // 默认分组测试方法 + public void validateEmployee(@Valid Employee employee) { + LOG.debug("Validating employee: {}", employee); + } + + public void validateAge(@Positive(message = "必须是正数") int age) { + LOG.debug("Validating age: {}", age); + } + + public void validateNameAndAge(@NotBlank String name, @Positive int age) { + LOG.debug("Validating name: {} and age: {}", name, age); + } + + // 分组验证代理方法 + public void validateAdvancedGroup(ValidationTestData data) { + if (advancedValidateService != null) { + advancedValidateService.validateAdvancedGroup(data); + } + } + + public void validateStudentAge(int age) { + if (studentValidateService != null) { + studentValidateService.validateStudentAge(age); + } + } + + public void validateTeacherAge(int age) { + if (teacherValidateService != null) { + teacherValidateService.validateTeacherAge(age); + } + } + + // 嵌套测试方法 + public void validateCompany(@Valid Company company) { + LOG.debug("Validating company: {}", company); + } + + public void validateEmployeeList(List<@Valid Employee> employees) { + LOG.debug("Validating employee list: {}", employees); + } + + public void validateNestedEmployeeList(List> nestedList) { + LOG.debug("Validating nested employee list: {}", nestedList); + } + + public void validateEmployeeMap(@Valid Map employeeMap) { + LOG.debug("Validating employee map: {}", employeeMap); + } + + public void validateEmployeeDataMap(@Valid Map map) { + LOG.debug("Validating employee data map: {}", map); + } + + public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map> nestedMap) { + LOG.debug("Validating nested employee data map: {}", nestedMap); + } + + public void validateEmployeeMapList(List> listOfMaps) { + LOG.debug("Validating employee map list: {}", listOfMaps); + } + + public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { + LOG.debug("Validating employee data list map: {}", map); + } + + public void validateCompanyList(@Valid List companies) { + LOG.debug("Validating company list: {}", companies); + } + + // 混合场景测试方法 + public void validateMixed(@Positive int value, @Valid Employee employee) { + LOG.debug("Validating mixed primitive {} and object {}", value, employee); + } + + public void validateMixedCollections(@NotNull List list1, @NotEmpty List list2) { + LOG.debug("Validating mixed collections: {} and {}", list1, list2); + } +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java new file mode 100644 index 000000000..79ab0d2c6 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + +import modelengine.fit.http.annotation.PostMapping; +import modelengine.fit.http.annotation.RequestBody; +import modelengine.fit.http.annotation.RequestMapping; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.validation.Validated; + +import javax.validation.Valid; + +/** + * 表示评估注解验证数据接口集。 + * + * @author 吕博文 + * @since 2024-08-15 + */ +@Component +@Validated +@RequestMapping(path = "/validation", group = "评估注解验证数据接口") +public class ValidationDataController { + /** + * Company 类默认分组注解验证。 + * + * @param company 表示注解验证类 {@link Company}。 + */ + @PostMapping(path = "/company/default", description = "验证 Company 类默认分组注解") + public void validateCompanyDefaultGroup(@RequestBody @Valid Company company) {} + + /** + * Company 类特定分组注解验证。 + * + * @param company 表示注解验证类 {@link Company}。 + */ + @PostMapping(path = "/company/companyGroup", description = "验证 Company 类特定分组注解") + public void validateCompanyGroup(@RequestBody @Valid Company company) {} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java new file mode 100644 index 000000000..5d8a9d928 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -0,0 +1,297 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation.data; + +import javax.validation.constraints.*; +import java.math.BigDecimal; +import java.time.LocalDate; + +/** + * 测试用的复杂验证数据类。 + * + * @since 2024-09-27 + */ +public class ValidationTestData { + + // 分组接口定义 + public interface BasicGroup {} + public interface AdvancedGroup {} + public interface StudentGroup {} + public interface TeacherGroup {} + + @NotBlank(message = "名称不能为空") + private String name; + + @Min(value = 0, message = "年龄必须大于等于0") + @Max(value = 150, message = "年龄必须小于等于150") + @Max(value = 200, message = "高级组年龄必须小于等于200", groups = AdvancedGroup.class) + private Integer age; + + @NotBlank(message = "描述不能为空") + private String description; + + @NotBlank(message = "内容不能为空白") + private String content; + + @Size(min = 2, max = 10, message = "标题长度必须在2-10之间") + private String title; + + @DecimalMin(value = "0.0", message = "价格必须大于等于0") + @DecimalMax(value = "999.99", message = "价格必须小于等于999.99") + private BigDecimal price; + + @Positive(message = "数量必须是正数") + private Integer quantity; + + @PositiveOrZero(message = "库存必须是正数或零") + private int stock; + + @Negative(message = "折扣必须是负数") + private BigDecimal discount; + + @NegativeOrZero(message = "债务必须是负数或零") + private int debt; + + @Digits(integer = 3, fraction = 2, message = "金额格式不正确") + private BigDecimal amount; + + @Past(message = "出生日期必须是过去时间") + private LocalDate birthDate; + + @PastOrPresent(message = "创建时间必须是过去或现在时间") + private LocalDate createDate; + + @Future(message = "到期时间必须是未来时间") + private LocalDate expireDate; + + @FutureOrPresent(message = "更新时间必须是未来或现在时间") + private LocalDate updateDate; + + @Pattern(regexp = "^[a-zA-Z]+$", message = "代码只能包含字母") + private String code; + + @Email(message = "邮箱格式不正确") + private String email; + + @AssertTrue(message = "必须同意条款") + private Boolean agreed; + + @AssertFalse(message = "必须取消订阅") + private boolean subscribed; + + // 构造函数 + public ValidationTestData() {} + + public ValidationTestData(String name, Integer age) { + this.name = name; + this.age = age; + } + + public ValidationTestData(String name, String description, String content, String title, + int age, BigDecimal price, int quantity, int stock, BigDecimal discount, + int debt, BigDecimal amount, LocalDate birthDate, LocalDate createDate, + LocalDate expireDate, LocalDate updateDate, String code, String email, + Boolean agreed, boolean subscribed) { + this.name = name; + this.description = description; + this.content = content; + this.title = title; + this.age = age; + this.price = price; + this.quantity = quantity; + this.stock = stock; + this.discount = discount; + this.debt = debt; + this.amount = amount; + this.birthDate = birthDate; + this.createDate = createDate; + this.expireDate = expireDate; + this.updateDate = updateDate; + this.code = code; + this.email = email; + this.agreed = agreed; + this.subscribed = subscribed; + } + + // Getters and Setters + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public int getStock() { + return stock; + } + + public void setStock(int stock) { + this.stock = stock; + } + + public BigDecimal getDiscount() { + return discount; + } + + public void setDiscount(BigDecimal discount) { + this.discount = discount; + } + + public int getDebt() { + return debt; + } + + public void setDebt(int debt) { + this.debt = debt; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public LocalDate getBirthDate() { + return birthDate; + } + + public void setBirthDate(LocalDate birthDate) { + this.birthDate = birthDate; + } + + public LocalDate getCreateDate() { + return createDate; + } + + public void setCreateDate(LocalDate createDate) { + this.createDate = createDate; + } + + public LocalDate getExpireDate() { + return expireDate; + } + + public void setExpireDate(LocalDate expireDate) { + this.expireDate = expireDate; + } + + public LocalDate getUpdateDate() { + return updateDate; + } + + public void setUpdateDate(LocalDate updateDate) { + this.updateDate = updateDate; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Boolean getAgreed() { + return agreed; + } + + public void setAgreed(Boolean agreed) { + this.agreed = agreed; + } + + public boolean isSubscribed() { + return subscribed; + } + + public void setSubscribed(boolean subscribed) { + this.subscribed = subscribed; + } + + @Override + public String toString() { + return "ValidationTestData{" + + "name='" + name + '\'' + + ", age=" + age + + ", description='" + description + '\'' + + ", content='" + content + '\'' + + ", title='" + title + '\'' + + ", price=" + price + + ", quantity=" + quantity + + ", stock=" + stock + + ", discount=" + discount + + ", debt=" + debt + + ", amount=" + amount + + ", birthDate=" + birthDate + + ", createDate=" + createDate + + ", expireDate=" + expireDate + + ", updateDate=" + updateDate + + ", code='" + code + '\'' + + ", email='" + email + '\'' + + ", agreed=" + agreed + + ", subscribed=" + subscribed + + '}'; + } +} diff --git a/framework/fit/java/fit-builtin/plugins/pom.xml b/framework/fit/java/fit-builtin/plugins/pom.xml index b4e52efd9..6878b97fb 100644 --- a/framework/fit/java/fit-builtin/plugins/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/pom.xml @@ -43,6 +43,8 @@ fit-service-discovery fit-service-registry fit-value-fastjson + fit-hibernate-validation-jakarta + fit-hibernate-validation From 9c6953190e88103eaeb58887411cdb91d3c2f110 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Fri, 18 Jul 2025 14:43:20 +0800 Subject: [PATCH 02/23] =?UTF-8?q?[fit]=20=E5=AE=9E=E7=8E=B0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E6=A0=A1=E9=AA=8C=E6=8F=92=E4=BB=B6=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81javax=EF=BC=8CJakarta=E6=A0=87=E5=87=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fitframework/validation/ValidationHandler.java | 6 +++--- .../validation/ValidationDataControllerTest.java | 6 +++--- .../fitframework/validation/ValidationHandlerTest.java | 6 +++--- .../modelengine/fitframework/validation/data/Company.java | 6 +++--- .../modelengine/fitframework/validation/data/Employee.java | 6 +++--- .../fitframework/validation/data/GroupValidateService.java | 6 +++--- .../fitframework/validation/data/ValidateService.java | 6 +++--- .../validation/data/ValidationDataController.java | 6 +++--- .../fitframework/validation/data/ValidationTestData.java | 5 +++-- .../fitframework/validation/ValidationHandler.java | 6 +++--- .../validation/ValidationDataControllerTest.java | 7 +++---- .../fitframework/validation/ValidationHandlerTest.java | 6 +++--- .../modelengine/fitframework/validation/data/Company.java | 6 +++--- .../modelengine/fitframework/validation/data/Employee.java | 6 +++--- .../fitframework/validation/data/GroupValidateService.java | 6 +++--- .../fitframework/validation/data/ValidateService.java | 6 +++--- .../validation/data/ValidationDataController.java | 6 +++--- .../fitframework/validation/data/ValidationTestData.java | 5 +++-- 18 files changed, 54 insertions(+), 53 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 66dbf8b38..b48e085bb 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -34,8 +34,8 @@ * 当调用的类或方法参数包含 {@link Validated} 注解时,会对该方法进行校验处理。 *

* - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ @Aspect(scope = Scope.GLOBAL) @Component diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java index d6cd04583..614a21be3 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -27,8 +27,8 @@ /** * {@link ValidationDataController} 的测试集。 * - * @author 吕博文 - * @since 2024-08-15 + * @author 阮睿 + * @since 2025-07-18 */ @MvcTest(classes = {ValidationDataController.class}) @DisplayName("测试 EvalDataController") diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index a3bb6980a..45b51c3db 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -32,8 +32,8 @@ /** * {@link ValidationHandler} 的单元测试。 * - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ @DisplayName("测试注解校验功能") @FitTestWithJunit(includeClasses = { diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java index 2bb304e7a..4cc02cca1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -15,8 +15,8 @@ /** * 公司实体类。 * - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ public class Company { @NotNull diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java index de383e2a5..f1808401c 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -12,8 +12,8 @@ /** * 员工实体类。 * - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ public class Employee { @NotBlank(message = "姓名不能为空") diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index ad9f47931..a3c936667 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -17,8 +17,8 @@ /** * 表示测试用分组校验服务。 * - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ @Component public class GroupValidateService { diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index ce53114a0..7c7a321f9 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -24,8 +24,8 @@ /** * 表示测试用校验服务。 * - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ @Component @Validated diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java index f8856f41b..f0c62886d 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -17,8 +17,8 @@ /** * 表示评估注解验证数据接口集。 * - * @author 吕博文 - * @since 2024-08-15 + * @author 阮睿 + * @since 2025-07-18 */ @Component @Validated diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index 65bfae98f..63d56492d 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -13,7 +13,8 @@ /** * 测试用的复杂验证数据类。 * - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ public class ValidationTestData { diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 79eb44f08..ab991a96a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -34,8 +34,8 @@ * 当调用的类或方法参数包含 {@link Validated} 注解时,会对该方法进行校验处理。 *

* - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ @Aspect(scope = Scope.GLOBAL) @Component diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java index d9b94b4b4..614a21be3 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -20,7 +20,6 @@ import org.junit.jupiter.api.Test; import java.io.IOException; -import java.util.Arrays; import java.util.Collections; import static org.assertj.core.api.Assertions.assertThat; @@ -28,8 +27,8 @@ /** * {@link ValidationDataController} 的测试集。 * - * @author 吕博文 - * @since 2024-08-15 + * @author 阮睿 + * @since 2025-07-18 */ @MvcTest(classes = {ValidationDataController.class}) @DisplayName("测试 EvalDataController") diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 50378b0e4..70a598db1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -32,8 +32,8 @@ /** * {@link ValidationHandler} 的单元测试。 * - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ @DisplayName("测试注解校验功能") @FitTestWithJunit(includeClasses = { diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Company.java index 9cfd8fab4..b503e037f 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Company.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -15,8 +15,8 @@ /** * 公司实体类。 * - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ public class Company { @NotNull diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Employee.java index 455ebe903..976ef05e0 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -12,8 +12,8 @@ /** * 员工实体类。 * - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ public class Employee { @NotBlank(message = "姓名不能为空") diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index 0254ec22c..8f769d031 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -17,8 +17,8 @@ /** * 表示测试用分组校验服务。 * - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ @Component public class GroupValidateService { diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index dfe8f1181..f9ef6155a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -24,8 +24,8 @@ /** * 表示测试用校验服务。 * - * @author 易文渊 - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ @Component @Validated diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java index 79ab0d2c6..5ce41bf3e 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -17,8 +17,8 @@ /** * 表示评估注解验证数据接口集。 * - * @author 吕博文 - * @since 2024-08-15 + * @author 阮睿 + * @since 2025-07-18 */ @Component @Validated diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index 5d8a9d928..56ab50d19 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -13,7 +13,8 @@ /** * 测试用的复杂验证数据类。 * - * @since 2024-09-27 + * @author 阮睿 + * @since 2025-07-18 */ public class ValidationTestData { From 8f2c753413ca6d0f27a920c822ef331583ad57b0 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Fri, 25 Jul 2025 13:00:48 +0800 Subject: [PATCH 03/23] =?UTF-8?q?[fit]=20=E4=BF=AE=E6=94=B9=E4=B8=8D?= =?UTF-8?q?=E5=BD=93=E7=9A=84=E6=A0=87=E5=87=86=E5=88=A4=E6=96=AD=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=EF=BC=8C=E6=8F=90=E4=BE=9B=E6=A0=A1=E9=AA=8C=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E4=BD=BF=E7=94=A8=E6=8C=87=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...37\350\203\275\347\273\204\344\273\266.md" | 337 ++++++++++++++++++ .../validation/ValidationHandler.java | 19 +- .../validation/ValidationHandler.java | 20 +- 3 files changed, 355 insertions(+), 21 deletions(-) diff --git "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" index b61170e4b..a356612ce 100644 --- "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" +++ "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" @@ -462,3 +462,340 @@ name.notnull=The name cant be null. // resources/i18n/default_zh.properties name.notnull=姓名不能为空。 ``` +# 12.4 Validation 插件 + +FIT框架提供了基于Hibernate Validator的数据校验功能,支持对方法参数进行自动校验。框架提供了两个版本的校验插件以适配不同的Java环境,与12.3的扩展校验实现不同在于,12.3只处理FIT框架提供的校验注解,而12.4则支持所有符合javax.validation规范或者jakarta.validation规范的校验注解: + +- `fit-hibernate-validation`:基于javax.validation规范,适用于传统Java EE环境 +- `fit-hibernate-validation-jakarta`:基于jakarta.validation规范,适用于Jakarta EE环境 + +约束由约束注解和约束验证实现的组合定义。约束注解可以应用于类、方法、字段或其他约束注解(在组合的情况下)。 + +## 12.4.1 依赖 + +根据您的Java环境选择对应的插件: + +**传统Java EE环境(javax):** +```xml + + org.fitframework.plugin + fit-hibernate-validation + 3.6.0-SNAPSHOT + +``` + +**Jakarta EE环境:** +```xml + + org.fitframework.plugin + fit-hibernate-validation-jakarta + 3.6.0-SNAPSHOT + +``` + +同时根据您的Java环境选择对应的标准依赖: + +**传统Java EE环境(javax):** +```xml + + javax.validation + validation-api + 2.0.2.Final + +``` + +**Jakarta EE环境:** +```xml + + jakarta.validation + jakarta.validation-api + 3.1.1 + +``` + +## 12.4.2 注解用法 + +### 基本用法 + +1. **类级别校验**:在类上添加`@Validated`注解,框架会自动对该类的所有方法参数进行校验。 + +```java +@Component +@Validated +public class UserController { + + public void createUser(@NotBlank(message = "用户名不能为空") String username, + @Min(value = 18, message = "年龄必须大于等于18") Integer age) { + // 业务逻辑 + } +} +``` + +2. **复杂对象校验**:对于复杂对象,需要在参数前添加`@Valid`注解,并在对象内部字段上添加校验注解。 + +```java +public class UserDto { + @NotBlank(message = "名称不能为空") + private String name; + + @Min(value = 0, message = "年龄必须大于等于0") + @Max(value = 150, message = "年龄必须小于等于150") + private Integer age; + + @Email(message = "邮箱格式不正确") + private String email; + + @Pattern(regexp = "^[a-zA-Z]+$", message = "代码只能包含字母") + private String code; + + // getter/setter... +} +``` + +```java +@PostMapping("/user") +public void createUser(@RequestBody @Valid UserDto userDto) { + // 业务逻辑 +} +``` + +### 泛型类型校验 + +3. **泛型类型参数校验**:方法的某个入参是泛型类型,如`Collection`、`Map`的参数类型,需要在校验对象前添加`@Valid`注解(按照hibernate validator reference推荐,但您仍然可以以@Valid List 这样的方式添加注解,但不能以@Valid List> 的方式添加注解),否则添加的约束规则不生效,并在泛型内部类型对需要校验的字段添加所需的校验注解。 + +```java +// List类型参数校验 +public void createUsers(List<@Valid UserDto> users) { + // 会对List中每个UserDto对象进行校验 +} + +// Map类型参数校验 +public void processUserData(Map userMap) { + // 会对Map中每个UserDto值进行校验 +} + +// Set类型参数校验 +public void updateUsers(Set @Valid users) { + // 会对Set中每个UserDto对象进行校验 +} +``` + +### 嵌套对象校验 + +4. **嵌套校验支持**:FIT支持对嵌套校验,即当泛型类型中内嵌泛型类型、非基本数据类型的字段中包含非基本数据类型时,需要在嵌套字段上添加`@Valid`注解。 + +```java +public class CompanyDto { + @NotBlank(message = "公司名称不能为空") + private String name; + + @Min(value = 0, message = "员工数量不能为负数") + private Integer employeeCount; + + // 嵌套单个对象校验 + @Valid + @NotNull(message = "经理信息不能为空") + private UserDto manager; + + // 嵌套集合对象校验 + @Valid + @Size(min = 1, message = "至少需要一个员工") + private List employees; + + // 嵌套Map对象校验 + @Valid + private Map departments; + + // getter/setter... +} + +public class DepartmentDto { + @NotBlank(message = "部门名称不能为空") + private String departmentName; + + @Valid + private List members; + + // getter/setter... +} + +// 使用示例 +public void createCompany(@Valid CompanyDto company) { + // 会递归校验company及其所有嵌套对象 +} + +// 复杂嵌套泛型校验 +public void processComplexData(Map> companyGroups) { + // 会校验Map中每个List,以及List中每个CompanyDto及其嵌套对象 +} +``` + +5. **校验失败处理**:方法被调用时,如果传入的实际参数与约束规则不符,会直接抛出`ConstraintViolationException`,表明参数校验失败。 + +### 支持的校验注解 + +框架支持完整的Bean Validation注解集合: + +#### 空值校验 +- `@NotNull`:值不能为null +- `@NotEmpty`:值不能为null且不能为空(适用于字符串、集合、数组、Map) +- `@NotBlank`:字符串不能为null、空字符串或只包含空白字符 +- `@Null`:值必须为null + +#### 布尔值校验 +- `@AssertTrue`:值必须为true +- `@AssertFalse`:值必须为false + +#### 数值校验 +- `@Min(value)`:数值必须大于等于指定值 +- `@Max(value)`:数值必须小于等于指定值 +- `@DecimalMin(value)`:小数值必须大于等于指定值 +- `@DecimalMax(value)`:小数值必须小于等于指定值 +- `@Positive`:数值必须为正数(大于0) +- `@PositiveOrZero`:数值必须为正数或零(大于等于0) +- `@Negative`:数值必须为负数(小于0) +- `@NegativeOrZero`:数值必须为负数或零(小于等于0) +- `@Digits(integer, fraction)`:数字格式校验,integer指定整数位数,fraction指定小数位数 + +#### 大小校验 +- `@Size(min, max)`:字符串、集合、数组、Map的大小必须在指定范围内 + +#### 时间校验 +- `@Past`:日期必须是过去的时间 +- `@PastOrPresent`:日期必须是过去或现在的时间 +- `@Future`:日期必须是未来的时间 +- `@FutureOrPresent`:日期必须是未来或现在的时间 + +#### 格式校验 +- `@Pattern(regexp)`:字符串必须匹配指定的正则表达式 +- `@Email`:字符串必须是有效的邮箱格式 + +#### 使用示例 + +```java +public class CompleteValidationDto { + @NotNull(message = "ID不能为空") + private Long id; + + @NotBlank(message = "用户名不能为空") + @Size(min = 2, max = 20, message = "用户名长度必须在2-20之间") + @Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母、数字和下划线") + private String username; + + @Email(message = "邮箱格式不正确") + private String email; + + @Min(value = 18, message = "年龄必须大于等于18") + @Max(value = 100, message = "年龄必须小于等于100") + private Integer age; + + @DecimalMin(value = "0.0", message = "薪资不能为负数") + @DecimalMax(value = "999999.99", message = "薪资不能超过999999.99") + @Digits(integer = 6, fraction = 2, message = "薪资格式不正确") + private BigDecimal salary; + + @Past(message = "生日必须是过去的日期") + private LocalDate birthday; + + @Future(message = "合同到期日必须是未来的日期") + private LocalDate contractEndDate; + + @AssertTrue(message = "必须同意用户协议") + private Boolean agreeTerms; + + @Size(min = 1, max = 5, message = "技能数量必须在1-5之间") + @Valid + private List skills; + + // getter/setter... +} +``` + +### 分组校验 + +支持校验分组功能,可以在不同场景下应用不同的校验规则: + +```java +public class UserDto { + // 分组接口定义 + public interface BasicGroup {} + public interface AdvancedGroup {} + public interface StudentGroup {} + public interface TeacherGroup {} + + @NotBlank(message = "名称不能为空") + private String name; + + + @Max(value = 200, message = "高级组年龄必须小于等于200", groups = AdvancedGroup.class) + private Integer age; + + // getter/setter... +} +``` + +```java +@Component +@Validated(UserDto.AdvancedGroup.class) +public class AdvancedUserService { + public void processAdvancedUser(@Valid UserDto user) { + // 只会应用AdvancedGroup分组的校验规则 + } +} +``` + +## 12.4.3 校验原理 + +### 核心组件 + +1. **ValidationHandler**:校验入口类,通过AOP方式拦截带有`@Validated`注解的类或方法,自动触发校验逻辑。 + +2. **Hibernate Validator**:底层使用Hibernate Validator作为校验引擎。 + +3. **ConstraintViolationException**:校验失败时抛出的异常,包含详细的错误信息。 + +### 校验流程 + +1. 当调用带有`@Validated`注解的类的方法时,`ValidationHandler`会拦截该调用 +2. 检查方法参数是否包含校验注解 +3. 使用Hibernate Validator对参数进行校验 +4. 如果校验失败,抛出`ConstraintViolationException`异常 +5. 可通过全局异常处理器捕获并处理校验异常 + +### 异常处理 + +```java +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(ConstraintViolationException.class) + public ResponseEntity> handleValidationException(ConstraintViolationException ex) { + StringBuilder message = new StringBuilder(); + for (ConstraintViolation violation : ex.getConstraintViolations()) { + message.append(violation.getMessage()).append("; "); + } + + ApiResponse response = new ApiResponse<>("ERROR", message.toString(), null); + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } +} +``` + +## 12.4.4 版本差异 + +两个插件的主要差异: + +| 特性 | fit-hibernate-validation | fit-hibernate-validation-jakarta | +|------|-------------------------|----------------------------------| +| 校验规范 | javax.validation | jakarta.validation | +| Hibernate版本 | 6.2.5.Final | 9.0.1.Final | +| 适用环境 | 传统Java EE | Jakarta EE | +| 包名空间 | javax.validation.* | jakarta.validation.* | + +选择建议: +- 新项目推荐使用Jakarta版本 +- 现有项目根据依赖情况选择对应版本 +- 两个版本功能完全一致,仅包名空间不同 + +## 12.4.5 校验的国际化 +与校验扩展一样,需要手动处理报错信息中的内容,以完成国际化功能 \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index b48e085bb..b9403271c 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -55,16 +55,15 @@ public ValidationHandler() { @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { // 检查方法参数是否包含被 javax.validation.Constraint 标注的校验注解 - if (hasJavaxConstraintAnnotations(joinPoint.getMethod().getParameters())) { - return; - } - ExecutableValidator execVal = this.validator.forExecutables(); - Set> result = execVal.validateParameters(joinPoint.getTarget(), - joinPoint.getMethod(), - joinPoint.getArgs(), - validated.value()); - if (!result.isEmpty()) { - throw new ConstraintViolationException(result); + if (!hasJavaxConstraintAnnotations(joinPoint.getMethod().getParameters())) { + ExecutableValidator execVal = this.validator.forExecutables(); + Set> result = execVal.validateParameters(joinPoint.getTarget(), + joinPoint.getMethod(), + joinPoint.getArgs(), + validated.value()); + if (!result.isEmpty()) { + throw new ConstraintViolationException(result); + } } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index ab991a96a..fac21256d 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -55,17 +55,15 @@ public class ValidationHandler implements AutoCloseable { @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { // 检查方法参数是否包含被 jakarta.validation.Constraint 标注的校验注解 - if (hasJakartaConstraintAnnotations(joinPoint.getMethod().getParameters())) { - return; - } - - ExecutableValidator execVal = this.validator.forExecutables(); - Set> result = execVal.validateParameters(joinPoint.getTarget(), - joinPoint.getMethod(), - joinPoint.getArgs(), - validated.value()); - if (!result.isEmpty()) { - throw new ConstraintViolationException(result); + if (!hasJakartaConstraintAnnotations(joinPoint.getMethod().getParameters())) { + ExecutableValidator execVal = this.validator.forExecutables(); + Set> result = execVal.validateParameters(joinPoint.getTarget(), + joinPoint.getMethod(), + joinPoint.getArgs(), + validated.value()); + if (!result.isEmpty()) { + throw new ConstraintViolationException(result); + } } } From 6152016809abdee55af08b58a0556e0edf9946ab Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Thu, 31 Jul 2025 12:29:22 +0800 Subject: [PATCH 04/23] =?UTF-8?q?[fit]=20=E5=B0=86handler=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E8=B4=A3=E4=BB=BB=E9=93=BE=E5=BD=A2=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/ValidationHandler.java | 57 ++++++++++++++---- .../validation/ValidationHandler.java | 58 +++++++++++++++---- 2 files changed, 95 insertions(+), 20 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index b9403271c..b73cf89da 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -17,6 +17,8 @@ import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedParameterizedType; +import java.lang.reflect.AnnotatedType; import java.lang.reflect.Parameter; import java.util.Arrays; import java.util.Set; @@ -55,7 +57,7 @@ public ValidationHandler() { @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { // 检查方法参数是否包含被 javax.validation.Constraint 标注的校验注解 - if (!hasJavaxConstraintAnnotations(joinPoint.getMethod().getParameters())) { + if (hasJakartaConstraintAnnotations(joinPoint.getMethod().getParameters())) { ExecutableValidator execVal = this.validator.forExecutables(); Set> result = execVal.validateParameters(joinPoint.getTarget(), joinPoint.getMethod(), @@ -74,30 +76,65 @@ public void close() { } /** - * 检查方法参数是否包含被 javax.validation.Constraint 标注的校验注解 + * 检查方法参数是否包含 jakarta.validation 校验注解 * * @param parameters 方法参数数组 - * @return 如果包含被 javax.validation.Constraint 标注的校验注解则返回 true,否则返回 false + * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false */ - private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { + private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { return Arrays.stream(parameters) - .flatMap(parameter -> Arrays.stream(parameter.getAnnotations())) - .anyMatch(this::isJavaxConstraintAnnotation); + .anyMatch(this::hasConstraintAnnotationsInParameter); } /** - * 检查注解是否被 javax.validation.Constraint 标注 + * 检查参数及其泛型类型参数是否包含校验注解 + * @param parameter 方法参数 + * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false + */ + private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { + return hasConstraintAnnotationsInType(parameter.getAnnotatedType()); + } + + /** + * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解 + * @param annotatedType 参数注解类型 + * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false + */ + private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { + // 检查当前类型上的注解 + if (Arrays.stream(annotatedType.getAnnotations()).anyMatch(this::isJakartaConstraintAnnotation)) { + return true; + } + + // 如果是参数化类型,递归检查类型参数 + if (annotatedType instanceof AnnotatedParameterizedType) { + AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) annotatedType; + return Arrays.stream(parameterizedType.getAnnotatedActualTypeArguments()) + .anyMatch(this::hasConstraintAnnotationsInType); + } + + return false; + } + + /** + * 检查注解是否属于 jakarta.validation 注解 * * @param annotation 要检查的注解 - * @return 如果被 javax.validation.Constraint 标注则返回 true,否则返回 false + * @return 如果属于 jakarta.validation 注解则返回 true,否则返回 false */ - private boolean isJavaxConstraintAnnotation(Annotation annotation) { + private boolean isJakartaConstraintAnnotation(Annotation annotation) { + // @Valid 注解检查 + if("jakarta.validation.Valid".equals(annotation.annotationType().getName())){ + return true; + } + // jakarta.validation.constraints, org.hibernate.validator.constraints 包下的注解检查 + // 通过 Constraint 注解检查当前注解是否为校验注解 Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); return Arrays.stream(metaAnnotations) .anyMatch(metaAnnotation -> { String packageName = metaAnnotation.annotationType().getPackage().getName(); String className = metaAnnotation.annotationType().getSimpleName(); - return "javax.validation".equals(packageName) && "Constraint".equals(className); + return "jakarta.validation".equals(packageName) && "Constraint".equals(className); }); } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index fac21256d..3c60ac98d 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -17,7 +17,10 @@ import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedParameterizedType; +import java.lang.reflect.AnnotatedType; import java.lang.reflect.Parameter; +import java.util.ArrayList; import java.util.Arrays; import java.util.Set; @@ -55,7 +58,7 @@ public class ValidationHandler implements AutoCloseable { @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { // 检查方法参数是否包含被 jakarta.validation.Constraint 标注的校验注解 - if (!hasJakartaConstraintAnnotations(joinPoint.getMethod().getParameters())) { + if (hasJavaxConstraintAnnotations(joinPoint.getMethod().getParameters())) { ExecutableValidator execVal = this.validator.forExecutables(); Set> result = execVal.validateParameters(joinPoint.getTarget(), joinPoint.getMethod(), @@ -74,30 +77,65 @@ public void close() { } /** - * 检查方法参数是否包含被 jakarta.validation.Constraint 标注的校验注解 + * 检查方法参数是否包含 javax.validation 校验注解 * * @param parameters 方法参数数组 - * @return 如果包含被 jakarta.validation.Constraint 标注的校验注解则返回 true,否则返回 false + * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false */ - private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { + private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { return Arrays.stream(parameters) - .flatMap(parameter -> Arrays.stream(parameter.getAnnotations())) - .anyMatch(this::isJakartaConstraintAnnotation); + .anyMatch(this::hasConstraintAnnotationsInParameter); } /** - * 检查注解是否被 jakarta.validation.Constraint 标注 + * 检查参数及其泛型类型参数是否包含校验注解 + * @param parameter 方法参数数组 + * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false + */ + private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { + return hasConstraintAnnotationsInType(parameter.getAnnotatedType()); + } + + /** + * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解 + * @param annotatedType 参数注解类型 + * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false + */ + private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { + // 检查当前类型上的注解 + if (annotatedType.getAnnotations().length > 0) { + return Arrays.stream(annotatedType.getAnnotations()).anyMatch(this::isJavaxConstraintAnnotation); + } + + // 如果是参数化类型,递归检查类型参数 + if (annotatedType instanceof AnnotatedParameterizedType) { + AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) annotatedType; + return Arrays.stream(parameterizedType.getAnnotatedActualTypeArguments()) + .anyMatch(this::hasConstraintAnnotationsInType); + } + + return false; + } + + /** + * 检查注解是否属于 javax.validation 注解 * * @param annotation 要检查的注解 - * @return 如果被 jakarta.validation.Constraint 标注则返回 true,否则返回 false + * @return 如果属于 javax.validation 注解则返回 true,否则返回 false */ - private boolean isJakartaConstraintAnnotation(Annotation annotation) { + private boolean isJavaxConstraintAnnotation(Annotation annotation) { + // @Valid 注解检查 + if(annotation.annotationType().getName().equals("javax.validation.Valid")){ + return true; + } + // javax.validation.constraints, org.hibernate.validator.constraints 包下的注解检查 + // 通过 Constraint 注解检查当前注解是否为校验注解 Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); return Arrays.stream(metaAnnotations) .anyMatch(metaAnnotation -> { String packageName = metaAnnotation.annotationType().getPackage().getName(); String className = metaAnnotation.annotationType().getSimpleName(); - return "jakarta.validation".equals(packageName) && "Constraint".equals(className); + return "javax.validation".equals(packageName) && "Constraint".equals(className); }); } } From 76167c7d034fdaad2277db39a3993a8773728d89 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Mon, 4 Aug 2025 12:50:52 +0800 Subject: [PATCH 05/23] =?UTF-8?q?[fit]=20=E4=BF=AE=E6=94=B9=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E4=BC=98=E5=85=88=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugins/fit-hibernate-validation-jakarta/pom.xml | 2 +- .../java/fit-builtin/plugins/fit-hibernate-validation/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml index 3dc97b234..ae2b7b03b 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml @@ -87,7 +87,7 @@ fit-build-maven-plugin system - 1 + 4 diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml index ca66ddcb4..d3f7f9387 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml @@ -87,7 +87,7 @@ fit-build-maven-plugin system - 1 + 4 From b187d7e934fda8eca026980616f92dd8ad34d4f1 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Thu, 7 Aug 2025 16:58:23 +0800 Subject: [PATCH 06/23] =?UTF-8?q?[fit]=20=E5=88=A0=E9=99=A4=E6=97=A7?= =?UTF-8?q?=E7=9A=84=E6=A0=A1=E9=AA=8C=E5=AE=9E=E7=8E=B0=E5=8F=8A=E5=85=B6?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...37\350\203\275\347\273\204\344\273\266.md" | 283 +--------- .../validation/ConstraintValidator.java | 41 -- .../fitframework/validation/Validated.java | 5 +- .../validation/constraints/Constraint.java | 31 -- .../validation/constraints/Min.java | 45 -- .../validation/constraints/NotBlank.java | 38 -- .../validation/constraints/NotEmpty.java | 38 -- .../validation/constraints/Positive.java | 38 -- .../validation/constraints/Range.java | 52 -- .../validation/validators/MinValidator.java | 52 -- .../validators/NotBlankValidator.java | 24 - .../validators/NotEmptyValidator.java | 43 -- .../validators/PositiveValidator.java | 26 - .../validation/validators/RangeValidator.java | 54 -- .../fit-validation-hibernate/pom.xml | 87 ---- .../validation/ValidationHandler.java | 68 --- .../src/main/resources/application.yml | 4 - .../validation/ValidationHandlerTest.java | 58 --- .../fitframework/validation/data/Company.java | 33 -- .../validation/data/Employee.java | 35 -- .../validation/data/ValidateService.java | 53 -- .../fit-extension/fit-validation/README.md | 179 ------- .../java/fit-extension/fit-validation/pom.xml | 60 --- .../validation/ConstraintViolation.java | 125 ----- .../validation/ValidationHandler.java | 381 -------------- .../validation/ValidationMetadata.java | 95 ---- .../domain/AbstractValidationMetadata.java | 55 -- .../validation/domain/ValidationField.java | 53 -- .../domain/ValidationParameter.java | 54 -- .../ConstraintViolationException.java | 67 --- .../validation/group/DefaultGroup.java | 15 - .../src/main/resources/application.yaml | 4 - .../ValidationDataControllerTest.java | 141 ----- .../validation/ValidationHandlerTest.java | 489 ------------------ .../validation/annotation/MaxSize.java | 46 -- .../fitframework/validation/data/Car.java | 63 --- .../validation/data/CarValidate.java | 42 -- .../fitframework/validation/data/Company.java | 52 -- .../validation/data/NestedValidate.java | 84 --- .../fitframework/validation/data/Product.java | 73 --- .../validation/data/ProductValidate.java | 24 - .../validation/data/StudentValidate.java | 29 -- .../data/ValidationDataController.java | 48 -- .../validation/group/NormalCarGroup.java | 15 - .../validation/group/OldCarGroup.java | 15 - .../validation/group/StudentGroup.java | 15 - .../validation/group/TeacherGroup.java | 15 - .../validator/MaxSizeValidator.java | 41 -- framework/fit/java/fit-extension/pom.xml | 2 - 49 files changed, 9 insertions(+), 3381 deletions(-) delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/ConstraintValidator.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Constraint.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Min.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/NotBlank.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/NotEmpty.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Positive.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Range.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/MinValidator.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/NotBlankValidator.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/NotEmptyValidator.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/PositiveValidator.java delete mode 100644 framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/RangeValidator.java delete mode 100644 framework/fit/java/fit-extension/fit-validation-hibernate/pom.xml delete mode 100644 framework/fit/java/fit-extension/fit-validation-hibernate/src/main/java/modelengine/fitframework/validation/ValidationHandler.java delete mode 100644 framework/fit/java/fit-extension/fit-validation-hibernate/src/main/resources/application.yml delete mode 100644 framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java delete mode 100644 framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/Company.java delete mode 100644 framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/Employee.java delete mode 100644 framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/ValidateService.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/README.md delete mode 100644 framework/fit/java/fit-extension/fit-validation/pom.xml delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ConstraintViolation.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ValidationMetadata.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/AbstractValidationMetadata.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/ValidationField.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/ValidationParameter.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/exception/ConstraintViolationException.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/group/DefaultGroup.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/main/resources/application.yaml delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/annotation/MaxSize.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Car.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/CarValidate.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Company.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/NestedValidate.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Product.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/ProductValidate.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/StudentValidate.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/NormalCarGroup.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/OldCarGroup.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/StudentGroup.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/TeacherGroup.java delete mode 100644 framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/validator/MaxSizeValidator.java diff --git "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" index a356612ce..919102f40 100644 --- "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" +++ "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" @@ -210,268 +210,17 @@ public class MyEventHandler implements EventHandler { } ``` -# 12.3 Validation -约束由约束注解和约束验证实现的组合定义。约束注解可以应用于类、方法、字段或其他约束注解(在组合的情况下)。 - -## 12.3.1 依赖 - -``` xml - - org.fitframework.extension - fit-validation - ${fit.version} - -``` - -## 12.3.2 注解用法 - -1. 方法的某个入参是基本数据类型,可直接在该参数前使用注解添加约束规则。 - - ``` java - public void test1(@NotEmpty String name) {} - ``` -2. 方法的某个入参是非基本数据类型,需要在该参数前添加 @Validated 注解,否则添加的约束规则不生效,并在该类内对需要校验的字段添加所需的校验注解。 - - ``` java - public class CreateProjectReq { - /** - * 请求序列号 - */ - @Range(min = 0, max = 10, message = "最多只能请求10个值!") - private Integer requestNum; - - /** - * 项目名称 - */ - @NotBlank(message = "项目名称不可为空") - private String projectName; - ... - } - - public CreateProjectReq createProject(@Validated CreateProjectReq reqVO) { - ... - } - ``` -3. 方法的某个入参是泛型类型,如`Collection`、`Map`的参数类型,需要在该参数前添加 @Validated 注解,否则添加的约束规则不生效,并在该类内对需要校验的字段添加所需的校验注解。 - - ``` java - public void test(@Validated List obj) {} - ``` -4. `FIT` 支持对嵌套校验,即当泛型类型中内嵌泛型类型、非基本数据类型的字段中包含非基本数据类型。 - - ``` java - public class Company { - @Range(min = 0, max = 1, message = "经理只能有0-1个!") - private int manager; - - @Validated - private Product product; - - @Validated - private List cars; - - ... - } - - public void test(@Validated Company) {} - public void test(@Validated Map) {} - ... - ``` -5. 方法被调用时,如果传入的实际参数与约束规则不符,会直接抛出 ConstraintViolationException ,表明参数校验失败。 - -## 12.3.3 校验原理 - -`modelengine.fitframework.validation`目前提供了部分额外的自定义校验注解,如`@NotBlank` 、`@NotEmpty`、`@Range`等,其逻辑可以参考`spring`对应注解的逻辑。 - -### 校验器接口 - -* 主要的检验逻辑由`modelengine.fitframework.validation.ConstraintValidator`接口定义。通过实现该接口,可以自定义校验器,并编写具体的校验逻辑。 -* 校验器接口定义了一个`isValid`方法,用于在给定的对象上进行校验。校验器将根据对象的类型和注解信息,逐一校验对象的属性。 - -### 校验过程 - -* 当接收到请求时,可以使用 `@Validated` 注解来标记要校验的对象。 -* 框架会查找对应的校验器,并在处理请求时自动调用校验器的 `validate` 方法进行校验。 -* 校验器会根据对象的注解信息,逐个校验对象的属性。如果发现校验失败,则构造一个 `modelengine.fitframework.validation.exception.ConstraintViolationException` 对象,并将校验失败的信息存入其中。 - -### 异常处理 - -* 在异常处理方法中,可以将异常中的校验错误信息提取出来,并按照需要进行处理,如包装成一个响应实体类返回给客户端。 - -总的来说,Validation 的源码逻辑主要涉及注解的定义、校验器的实现以及校验过程的触发和异常处理。校验器会根据注解信息逐一校验对象的属性,当遇到错误时,将错误信息存入 `ConstraintViolationException` 中,并通过异常处理机制将错误信息返回给客户端。这样可以实现灵活、便捷的校验功能,并提高开发效率和错误处理的友好性。 - -## 12.3.4 自定义校验注解 - -上述提供注解只是最通用的验证规则,对于千奇百怪的业务需求,显然是不满足的。因此用户可以自定义注解,实现符合自身业务逻辑的校验逻辑,只需要两步即可拥有自定义注解。 - -### 创建一个约束注解 - -示例如下: - -``` java -@Retention(RetentionPolicy.RUNTIME) -@Constraint(MaxLengthValidator.class) -@Validated -public @interface MaxLength { - /** - * 表示校验失败的信息。 - * - * @return 表示校验失败的信息的 {@link String}。 - */ - String message() default ""; - - /** - * 表示校验的分组。 - * - * @return 表示校验分组的 {@link Class}{@code []}。 - */ - Class[] groups() default {}; - - /** - * 表示校验的最大值。 - */ - long max(); -} -``` - -上述逻辑为自定义一个名为@MaxLength的注解,下面分别介绍每一部分的逻辑含义: - -1. @Retention(RetentionPolicy.RUNTIME) 表示 Java 注解中的元注解(即注解的注解),用于指定注解的保留策略。RUNTIME表示在运行时保留此注解,程序可以通过反射在运行期间获取该注解的信息。 -2. Constraint(MaxLengthValidator.class) `@Constraint` 是一个元注解,用于自定义验证约束注解时标注在自定义的验证约束注解上。该注解的意义是指定该注解所表示的验证约束注解需要使用哪些验证器对被注解的元素进行验证。示例中的`MaxLengthValidator`即为`@MaxLength`的验证器。 -3. `@Validated` 注解的含义是用于标记一个自定义注解 `@MaxLength`,指示该注解需要进行验证。`@Validated` 注解通常与校验框架结合使用,用于触发对被注解元素的校验。 -4. 定义注解`@MaxLength` -5. 表示校验失败的信息,默认值为空。用户可以在使用注解时,定义校验失败时的信息。 -6. 表示校验分组,其逻辑将会在下一节**分组校验**中详细介绍。 -7. 表示校验的最大值,由于其没有定义默认值,因此在使用注解时,需要将`max`值添加到注解中。 - -### 实现一个validator - -MaxLengthValidator验证器定义: - -``` java -@Component -public class MaxLengthValidator implements ConstraintValidator { - private long max; - - @Override - public void initialize(MaxLength constraintAnnotation) { - this.max = constraintAnnotation.max(); - } - - @Override - public boolean isValid(String value) { - return value != null && value.length() <= this.max; - } -} -``` - -validatior的实现非常简单,`ConstraintValidator`接口。 - -1. initialize方法,顾名思义是做一些初始化工作,获取约束的元数据并将它们存储在validator的实例中。 -2. isValid,实际的验证逻辑。 - -使用自定义约束@MaxLength注解: - -``` java -@MaxLength(message = "用户名(from User2)不能大于10", max = 10) -private final String name; -``` +# 12.3 Validation 插件 -## 12.3.5 分组校验 - -每个约束注解都必须定义一个 `groups` 元素,用于指定约束声明所关联的处理组。`groups` 允许在验证过程中限制应用的约束集。所定位的组将作为参数传递给 `isValid`方法。所有属于目标组的约束都将应用于验证过程中。如果没有传递组,则默认为空数组。 - -``` java -Class[] groups() default {}; -``` - -如果在一个元素上声明约束时未指定组,则默认组为 Default 组。组通常用于控制约束的评估顺序,或者用于验证 JavaBean 的部分状态。当在验证方法中传递了多个组时,顺序并不被限制。 - -``` java -public interface GroupA {} - -public interface GroupB {} - -public class Address { - @NotEmpty(groups = GroupA.class) - @MaxLength(max=50) - private String street; - - @NotEmpty - private String city; - - @NotEmpty(groups = {GroupA.class, GroupB.class}) - private String zipCode; - ... -} -``` - -在上述示例中,Address 类中`@NotEmpty`(及其组成的约束)适用于`GroupA`,`@MaxLength`在 `street`上适用于默认组,`Empty`(及其组成的约束)在`zipCode`上适用于`GroupA`和`GroupB`组。 - -当运行以下代码: - -``` java -validator.isValid(address) -``` - -`street`与`zipCode`字段上的`@NotEmpty`约束不会生效,生效的仅为`street`字段的`@MaxLength`注解以及`city`字段的`NotEmpty`注解。 - -当运行以下代码时: - -```` -validator.isValid(address, GroupA.class, GroupB.class) -```` - -`street`与`zipCode`字段上的`@NotEmpty`约束会生效,`street`字段的`@MaxLength`注解以及`city`字段的`NotEmpty`注解则不会生效。 - -当运行以下代码时: - -```` -validator.isValid(address, GroupB.class) -```` - -`zipCode`字段上的`@NotEmpty`约束会生效,其他字段的注解都不会生效。 - -## 12.3.6 校验的国际化 - -`FIT`提供`@Notmpty, @NotBlank, @Range, @Postive, @Min`支持当校验失败时抛出自定义信息,示例用法如下, -同时,如2.6.3.4所述,支持用户自定义注解及处理器,当实现message()方法,可实现同样功能。 - -``` java -@NotBlank(message = "姓名不能为空") -private String name; -``` - -当校验失败后,自定义的异常信息会被`FIT`整合后抛出`ConstraintViolationException`,在国际化场景下需要对该异常进行国际化处理,`FIT`支持简单的实现方式: - -1. 定义国际化信息的资源文件; -2. 在校验注解的`message`中使用`{xxxxx}`来表明国际化,其中xxxx是1所定义的国际化资源文件中的key; -3. 按照 2.6.1 的介绍进行国际化处理。 - -示例: - -``` java -@NotBlank(message ="{name.notnull}") -private String name; -``` - -``` yml -// resources/i18n/default_en.properties -name.notnull=The name cant be null. -// resources/i18n/default_zh.properties -name.notnull=姓名不能为空。 -``` -# 12.4 Validation 插件 - -FIT框架提供了基于Hibernate Validator的数据校验功能,支持对方法参数进行自动校验。框架提供了两个版本的校验插件以适配不同的Java环境,与12.3的扩展校验实现不同在于,12.3只处理FIT框架提供的校验注解,而12.4则支持所有符合javax.validation规范或者jakarta.validation规范的校验注解: +FIT框架提供了基于Hibernate Validator的数据校验功能,支持对方法参数进行自动校验。框架提供了两个版本的校验插件以适配不同的Java环境,与12.3的扩展校验实现不同在于,12.3只处理FIT框架提供的校验注解,而12.3则支持所有符合javax.validation规范或者jakarta.validation规范的校验注解: - `fit-hibernate-validation`:基于javax.validation规范,适用于传统Java EE环境 - `fit-hibernate-validation-jakarta`:基于jakarta.validation规范,适用于Jakarta EE环境 约束由约束注解和约束验证实现的组合定义。约束注解可以应用于类、方法、字段或其他约束注解(在组合的情况下)。 -## 12.4.1 依赖 +## 12.3.1 依赖 根据您的Java环境选择对应的插件: @@ -513,7 +262,7 @@ FIT框架提供了基于Hibernate Validator的数据校验功能,支持对方 ``` -## 12.4.2 注解用法 +## 12.3.2 注解用法 ### 基本用法 @@ -744,7 +493,7 @@ public class AdvancedUserService { } ``` -## 12.4.3 校验原理 +## 12.3.3 校验原理 ### 核心组件 @@ -762,26 +511,8 @@ public class AdvancedUserService { 4. 如果校验失败,抛出`ConstraintViolationException`异常 5. 可通过全局异常处理器捕获并处理校验异常 -### 异常处理 - -```java -@RestControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(ConstraintViolationException.class) - public ResponseEntity> handleValidationException(ConstraintViolationException ex) { - StringBuilder message = new StringBuilder(); - for (ConstraintViolation violation : ex.getConstraintViolations()) { - message.append(violation.getMessage()).append("; "); - } - - ApiResponse response = new ApiResponse<>("ERROR", message.toString(), null); - return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); - } -} -``` -## 12.4.4 版本差异 +## 12.3.4 版本差异 两个插件的主要差异: @@ -797,5 +528,5 @@ public class GlobalExceptionHandler { - 现有项目根据依赖情况选择对应版本 - 两个版本功能完全一致,仅包名空间不同 -## 12.4.5 校验的国际化 +## 12.3.5 校验的国际化 与校验扩展一样,需要手动处理报错信息中的内容,以完成国际化功能 \ No newline at end of file diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/ConstraintValidator.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/ConstraintValidator.java deleted file mode 100644 index 759034e7b..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/ConstraintValidator.java +++ /dev/null @@ -1,41 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation; - -import java.lang.annotation.Annotation; - -/** - * 表示约束的校验器类。 - * - * @author 邬涨财 - * @since 2023-03-08 - */ -public interface ConstraintValidator { - /** - * 校验器类的初始方法。每一个校验器对象都只会调用一次。 - * - * @param constraintAnnotation 表示约束注解的 {@link A}。 - */ - default void initialize(A constraintAnnotation) {} - - /** - * 校验对象是否合法。 - * - * @param value 表示需要校验的目标对象的 {@link T}。 - * @return 表示校验对象是否合法的 {@code boolean}。 - */ - boolean isValid(T value); - - /** - * 获取校验器的参数。 - * - * @return 表示校验器参数的 {@link Object}{@code []}。 - */ - default Object[] args() { - return new Object[] {}; - } -} diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java index a3a56c85b..5cfe2f7e1 100644 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java +++ b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java @@ -6,7 +6,6 @@ package modelengine.fitframework.validation; -import modelengine.fitframework.validation.constraints.Constraint; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -15,8 +14,8 @@ /** * 表示校验的注解。 - *

用来标识所要校验的类和参数。若校验的是类,则该类方法的所有带有 {@link Constraint} - * 参数会被校验;若校验的是参数,则校验该参数对象所有的带有 {@link Constraint} 字段。 + *

用来标识所要校验的类,该类的所有公共方法中,所有被 javax 或 jakarta 校验注解 + * 标注的参数都会被校验 *

* * @author 邬涨财 diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Constraint.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Constraint.java deleted file mode 100644 index 580179711..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Constraint.java +++ /dev/null @@ -1,31 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.constraints; - -import modelengine.fitframework.validation.ConstraintValidator; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * 表示约束的注解。 - * - * @author 邬涨财 - * @since 2023-03-08 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.ANNOTATION_TYPE}) -public @interface Constraint { - /** - * 表示约束所对应的校验器的类型。 - * - * @return 表示校验器的类型的 {@link Class}{@code >[]}。 - */ - Class>[] value(); -} diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Min.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Min.java deleted file mode 100644 index aeea6faa3..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Min.java +++ /dev/null @@ -1,45 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.constraints; - -import modelengine.fitframework.validation.Validated; -import modelengine.fitframework.validation.validators.MinValidator; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * 表示校验元素是否满足下限值约束的注解。 - * - * @author 兰宇晨 - * @since 2024-08-28 - */ -@Retention(RetentionPolicy.RUNTIME) -@Constraint(MinValidator.class) -@Validated -public @interface Min { - /** - * 表示校验元素的下限值。 - * - * @return 表示校验元素的下限值的 {@code long}。 - */ - long min(); - - /** - * 表示校验失败的信息。 - * - * @return 表示校验失败的信息的 {@link String}。 - */ - String message() default "must be greater than the minimum value."; - - /** - * 表示校验的分组。 - * - * @return 表示校验分组的 {@link Class}{@code []}。 - */ - Class[] groups() default {}; -} diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/NotBlank.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/NotBlank.java deleted file mode 100644 index ec92f9801..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/NotBlank.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.constraints; - -import modelengine.fitframework.validation.Validated; -import modelengine.fitframework.validation.validators.NotBlankValidator; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * 表示校验元素是否为空白的注解。 - * - * @author 邬涨财 - * @since 2023-03-08 - */ -@Retention(RetentionPolicy.RUNTIME) -@Constraint(NotBlankValidator.class) -@Validated -public @interface NotBlank { - /** - * 表示校验失败的信息。 - * - * @return 表示校验失败的信息的 {@link String}。 - */ - String message() default "must not be blank"; - - /** - * 表示校验的分组。 - * - * @return 表示校验分组的 {@link Class}{@code []}。 - */ - Class[] groups() default {}; -} diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/NotEmpty.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/NotEmpty.java deleted file mode 100644 index f3cfbceff..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/NotEmpty.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.constraints; - -import modelengine.fitframework.validation.Validated; -import modelengine.fitframework.validation.validators.NotEmptyValidator; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * 表示校验元素是否为空的注解。 - * - * @author 邬涨财 - * @since 2023-03-08 - */ -@Retention(RetentionPolicy.RUNTIME) -@Constraint(NotEmptyValidator.class) -@Validated -public @interface NotEmpty { - /** - * 表示校验失败的信息。 - * - * @return 表示校验失败的信息的 {@link String}。 - */ - String message() default "must not be empty"; - - /** - * 表示校验的分组。 - * - * @return 表示校验分组的 {@link Class}{@code []}。 - */ - Class[] groups() default {}; -} diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Positive.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Positive.java deleted file mode 100644 index 9c82f190d..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Positive.java +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.constraints; - -import modelengine.fitframework.validation.Validated; -import modelengine.fitframework.validation.validators.PositiveValidator; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * 表示判断元素值是否为正的注解。 - * - * @author 吕博文 - * @since 2024-08-01 - */ -@Retention(RetentionPolicy.RUNTIME) -@Constraint(PositiveValidator.class) -@Validated -public @interface Positive { - /** - * 表示校验失败的信息。 - * - * @return 表示校验失败的信息的 {@link String}。 - */ - String message() default "must be positive"; - - /** - * 表示校验的分组。 - * - * @return 表示校验分组的 {@link Class}{@code []}。 - */ - Class[] groups() default {}; -} diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Range.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Range.java deleted file mode 100644 index a5d64104a..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/constraints/Range.java +++ /dev/null @@ -1,52 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.constraints; - -import modelengine.fitframework.validation.Validated; -import modelengine.fitframework.validation.validators.RangeValidator; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * 表示校验元素是否为空的注解。 - * - * @author 邬涨财 - * @since 2023-03-08 - */ -@Retention(RetentionPolicy.RUNTIME) -@Constraint(RangeValidator.class) -@Validated -public @interface Range { - /** - * 表示校验元素的下限值。 - * - * @return 表示校验元素的下限值的 {@code long}。 - */ - long min(); - - /** - * 表示校验元素的上限值。 - * - * @return 表示校验元素的上限值的 {@code long}。 - */ - long max(); - - /** - * 表示校验失败的信息。 - * - * @return 表示校验失败的信息的 {@link String}。 - */ - String message() default "must be in range"; - - /** - * 表示校验的分组。 - * - * @return 表示校验分组的 {@link Class}{@code []}。 - */ - Class[] groups() default {}; -} diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/MinValidator.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/MinValidator.java deleted file mode 100644 index a6dedac92..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/MinValidator.java +++ /dev/null @@ -1,52 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.validators; - -import modelengine.fitframework.util.ObjectUtils; -import modelengine.fitframework.validation.ConstraintValidator; -import modelengine.fitframework.validation.constraints.Min; - -/** - * 表示 {@link Min} 约束的校验器。 - * - * @author 兰宇晨 - * @since 2024-08-28 - */ -public class MinValidator implements ConstraintValidator { - private long min; - - @Override - public void initialize(Min constraintAnnotation) { - this.min = constraintAnnotation.min(); - } - - @Override - public boolean isValid(Object value) { - if (value == null) { - return false; - } else if (value instanceof Integer) { - int convertedValue = ObjectUtils.cast(value); - return convertedValue >= this.min; - } else if (value instanceof Long) { - long convertedValue = ObjectUtils.cast(value); - return convertedValue >= this.min; - } else if (value instanceof Float) { - float convertedValue = ObjectUtils.cast(value); - return convertedValue >= this.min; - } else if (value instanceof Double) { - double convertedValue = ObjectUtils.cast(value); - return convertedValue >= this.min; - } else { - throw new UnsupportedOperationException("Failed to validate value: invalid value."); - } - } - - @Override - public Object[] args() { - return new Object[] {this.min}; - } -} \ No newline at end of file diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/NotBlankValidator.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/NotBlankValidator.java deleted file mode 100644 index 5ec02ee3c..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/NotBlankValidator.java +++ /dev/null @@ -1,24 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.validators; - -import modelengine.fitframework.util.StringUtils; -import modelengine.fitframework.validation.ConstraintValidator; -import modelengine.fitframework.validation.constraints.NotBlank; - -/** - * 表示 {@link NotBlank} 约束的校验器。 - * - * @author 邬涨财 - * @since 2023-03-08 - */ -public class NotBlankValidator implements ConstraintValidator { - @Override - public boolean isValid(String value) { - return StringUtils.isNotBlank(value); - } -} diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/NotEmptyValidator.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/NotEmptyValidator.java deleted file mode 100644 index 5c5d46e95..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/NotEmptyValidator.java +++ /dev/null @@ -1,43 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.validators; - -import modelengine.fitframework.util.ArrayUtils; -import modelengine.fitframework.util.CollectionUtils; -import modelengine.fitframework.util.MapUtils; -import modelengine.fitframework.util.ObjectUtils; -import modelengine.fitframework.util.StringUtils; -import modelengine.fitframework.validation.ConstraintValidator; -import modelengine.fitframework.validation.constraints.NotEmpty; - -import java.util.List; -import java.util.Map; - -/** - * 表示 {@link NotEmpty} 约束的校验器。 - * - * @author 邬涨财 - * @since 2023-03-08 - */ -public class NotEmptyValidator implements ConstraintValidator { - @Override - public boolean isValid(Object value) { - if (value == null) { - return false; - } else if (value instanceof List) { - return CollectionUtils.isNotEmpty(ObjectUtils.cast(value)); - } else if (value instanceof Map) { - return MapUtils.isNotEmpty(ObjectUtils.cast(value)); - } else if (value instanceof String) { - return StringUtils.isNotEmpty(ObjectUtils.cast(value)); - } else if (value instanceof Object[]) { - return ArrayUtils.isNotEmpty(ObjectUtils.cast(value)); - } else { - throw new UnsupportedOperationException("Failed to validate value: invalid value."); - } - } -} diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/PositiveValidator.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/PositiveValidator.java deleted file mode 100644 index d6a5e9999..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/PositiveValidator.java +++ /dev/null @@ -1,26 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.validators; - -import modelengine.fitframework.validation.ConstraintValidator; -import modelengine.fitframework.validation.constraints.Positive; - -/** - * 表示 {@link Positive} 约束的校验器。 - * - * @author 吕博文 - * @since 2024-07-29 - */ -public class PositiveValidator implements ConstraintValidator { - @Override - public boolean isValid(Number value) { - if (value == null) { - return false; - } - return value.doubleValue() > 0; - } -} diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/RangeValidator.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/RangeValidator.java deleted file mode 100644 index 3f80592df..000000000 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/validators/RangeValidator.java +++ /dev/null @@ -1,54 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.validators; - -import modelengine.fitframework.util.ObjectUtils; -import modelengine.fitframework.validation.ConstraintValidator; -import modelengine.fitframework.validation.constraints.Range; - -/** - * 表示 {@link Range} 约束的校验器。 - * - * @author 邬涨财 - * @since 2023-03-08 - */ -public class RangeValidator implements ConstraintValidator { - private long min; - private long max; - - @Override - public void initialize(Range constraintAnnotation) { - this.min = constraintAnnotation.min(); - this.max = constraintAnnotation.max(); - } - - @Override - public boolean isValid(Object value) { - if (value == null) { - return false; - } else if (value instanceof Integer) { - int convertedValue = ObjectUtils.cast(value); - return convertedValue >= this.min && convertedValue <= this.max; - } else if (value instanceof Long) { - long convertedValue = ObjectUtils.cast(value); - return convertedValue >= this.min && convertedValue <= this.max; - } else if (value instanceof Float) { - float convertedValue = ObjectUtils.cast(value); - return convertedValue >= this.min && convertedValue <= this.max; - } else if (value instanceof Double) { - double convertedValue = ObjectUtils.cast(value); - return convertedValue >= this.min && convertedValue <= this.max; - } else { - throw new UnsupportedOperationException("Failed to validate value: invalid value."); - } - } - - @Override - public Object[] args() { - return new Object[] {this.min, this.max}; - } -} diff --git a/framework/fit/java/fit-extension/fit-validation-hibernate/pom.xml b/framework/fit/java/fit-extension/fit-validation-hibernate/pom.xml deleted file mode 100644 index 07394cfaf..000000000 --- a/framework/fit/java/fit-extension/fit-validation-hibernate/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - 4.0.0 - - - org.fitframework.extension - fit-extension-parent - 3.6.0-SNAPSHOT - - - fit-validation-hibernate - - FIT Validation Hibernate - FIT Framework Validation Hibernate module provides validation functionality based on Hibernate - Validator implementation. - - https://github.com/ModelEngine-Group/fit-framework - - - - 6.2.5.Final - - - - - - org.fitframework - fit-api - - - - - org.hibernate.validator - hibernate-validator - ${hibernate.version} - - - - - org.junit.jupiter - junit-jupiter - test - - - org.mockito - mockito-core - test - - - org.assertj - assertj-core - test - - - org.fitframework - fit-test-framework - test - - - com.h2database - h2 - test - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-dependencies - - copy-dependencies - - - ../../../../../build/shared/ - jakarta.validation - - - - - - - diff --git a/framework/fit/java/fit-extension/fit-validation-hibernate/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-extension/fit-validation-hibernate/src/main/java/modelengine/fitframework/validation/ValidationHandler.java deleted file mode 100644 index 0aeb50301..000000000 --- a/framework/fit/java/fit-extension/fit-validation-hibernate/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation; - -import modelengine.fitframework.annotation.Component; -import modelengine.fitframework.aop.JoinPoint; -import modelengine.fitframework.aop.annotation.Aspect; -import modelengine.fitframework.aop.annotation.Before; -import modelengine.fitframework.ioc.annotation.PreDestroy; - -import org.hibernate.validator.HibernateValidator; -import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; - -import java.util.Set; - -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; -import javax.validation.executable.ExecutableValidator; - -/** - * 校验入口类。 - *

- * 当调用的类或方法参数包含 {@link Validated} 注解时,会对该方法进行校验处理。 - *

- * - * @author 易文渊 - * @since 2024-09-27 - */ -@Aspect -@Component -public class ValidationHandler implements AutoCloseable { - private final ValidatorFactory validatorFactory; - private final Validator validator; - - ValidationHandler() { - this.validatorFactory = Validation.byProvider(HibernateValidator.class) - .configure() - .messageInterpolator(new ParameterMessageInterpolator()) - .failFast(false) - .buildValidatorFactory(); - this.validator = validatorFactory.getValidator(); - } - - @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") - private void handle(JoinPoint joinPoint, Validated validated) { - ExecutableValidator execVal = this.validator.forExecutables(); - Set> result = execVal.validateParameters(joinPoint.getTarget(), - joinPoint.getMethod(), - joinPoint.getArgs(), - validated.value()); - if (!result.isEmpty()) { - throw new ConstraintViolationException(result); - } - } - - @PreDestroy - @Override - public void close() { - this.validatorFactory.close(); - } -} \ No newline at end of file diff --git a/framework/fit/java/fit-extension/fit-validation-hibernate/src/main/resources/application.yml b/framework/fit/java/fit-extension/fit-validation-hibernate/src/main/resources/application.yml deleted file mode 100644 index f9de2211d..000000000 --- a/framework/fit/java/fit-extension/fit-validation-hibernate/src/main/resources/application.yml +++ /dev/null @@ -1,4 +0,0 @@ -fit: - beans: - packages: - - 'modelengine.fitframework.validation' diff --git a/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java deleted file mode 100644 index e7dd155d2..000000000 --- a/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import modelengine.fitframework.annotation.Fit; -import modelengine.fitframework.test.annotation.FitTestWithJunit; -import modelengine.fitframework.validation.data.Company; -import modelengine.fitframework.validation.data.Employee; -import modelengine.fitframework.validation.data.ValidateService; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.Collections; - -import javax.validation.ConstraintViolationException; - -/** - * {@link ValidationHandler} 的单元测试。 - * - * @author 易文渊 - * @since 2024-09-27 - */ -@DisplayName("测试注解校验功能") -@FitTestWithJunit(includeClasses = {ValidateService.class, ValidationHandler.class}) -public class ValidationHandlerTest { - @Fit - private ValidateService validateService; - - @Test - @DisplayName("测试校验原始类型成功") - void givePrimitiveThenValidateOk() { - assertThatThrownBy(() -> this.validateService.foo0(-1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是正数"); - } - - @Test - @DisplayName("测试校验结构体成功") - void giveClassThenValidateOk() { - assertThatThrownBy(() -> this.validateService.foo1(new Employee("sky", 17))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("年龄必须大于等于18"); - } - - @Test - @DisplayName("测试嵌套结构体成功") - void giveNestedClassThenValidateOk() { - assertThatThrownBy(() -> { - Employee employee = new Employee("sky", 17); - this.validateService.foo2(new Company(Collections.singletonList(employee))); - }).isInstanceOf(ConstraintViolationException.class).hasMessageContaining("年龄必须大于等于18"); - } -} diff --git a/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/Company.java deleted file mode 100644 index 0cc9dfe39..000000000 --- a/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/Company.java +++ /dev/null @@ -1,33 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import java.util.List; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** - * 公司 pojo。 - * - * @author 易文渊 - * @since 2024-09-27 - */ -public class Company { - @Valid - @NotNull(message = "雇员列表不能为空") - List<@Valid @NotNull Employee> employees; - - /** - * 构建函数。 - * - * @param employees 表示雇员列表的 {@link List}{@code <}{@link Employee}{@code >}。 - */ - public Company(List employees) { - this.employees = employees; - } -} \ No newline at end of file diff --git a/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/Employee.java deleted file mode 100644 index 4217505fb..000000000 --- a/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ /dev/null @@ -1,35 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; - -/** - * 雇员 pojo。 - * - * @author 易文渊 - * @since 2024-09-27 - */ -public class Employee { - @NotBlank - private String name; - - @Min(value = 18, message = "年龄必须大于等于18") - private int age; - - /** - * 构造函数。 - * - * @param name 表示用户名字的 {@link String}。 - * @param age 表示用户年龄的 {@code int}。 - */ - public Employee(String name, int age) { - this.name = name; - this.age = age; - } -} \ No newline at end of file diff --git a/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/ValidateService.java deleted file mode 100644 index e47915261..000000000 --- a/framework/fit/java/fit-extension/fit-validation-hibernate/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ /dev/null @@ -1,53 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fitframework.annotation.Component; -import modelengine.fitframework.log.Logger; -import modelengine.fitframework.validation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.Positive; - -/** - * 表示测试用校验服务。 - * - * @author 易文渊 - * @since 2024-09-27 - */ -@Component -@Validated -public class ValidateService { - private static final Logger LOG = Logger.get(ValidateService.class); - - /** - * 测试原始类型。 - * - * @param num 表示输入的 {@code int}。 - */ - public void foo0(@Positive(message = "必须是正数") int num) { - LOG.debug("{}", num); - } - - /** - * 测试结构体类型。 - * - * @param employee 表示输入的 {@code Employee}。 - */ - public void foo1(@Valid Employee employee) { - LOG.debug("{}", employee); - } - - /** - * 测试嵌套类型。 - * - * @param company 表示输入的 {@code Company}。 - */ - public void foo2(@Valid Company company) { - LOG.debug("{}", company); - } -} \ No newline at end of file diff --git a/framework/fit/java/fit-extension/fit-validation/README.md b/framework/fit/java/fit-extension/fit-validation/README.md deleted file mode 100644 index e7fc016f6..000000000 --- a/framework/fit/java/fit-extension/fit-validation/README.md +++ /dev/null @@ -1,179 +0,0 @@ -
Validation Architecture
- -# 核心类图 - -``` plantuml - -@startuml -hide empty members - -skinparam backgroundColor #EEEBDC -skinparam roundcorner 20 -skinparam sequenceArrowThickness 2 -skinparam ClassFontName Consolas - -skinparam class { -BackgroundColor<> LightGray -BackgroundColor<> Pink -} - -class ValidationHandler { - - validator : Validator - -- - - handle(ProceedingJoinPoint joinPoint) : Object - === - This class as the entry of the validation capability and automatically scans the validator annotation during startup. - Therefore, the handle method is private and is not provided externally. -} - -interface ConstraintValidator { - + {abstract} initialize(Annotation constraintAnnotation) : void - + {abstract} isValid(T value) : void - === - Represents a constraint validator that validates a specific constraint. - The specific constraint is represented by an annotation. -} -annotation Constraint -Constraint .left.> ConstraintValidator - -interface ConstraintViolation { - + {abstract} message() : String - + {abstract} message(String value) : void - + {abstract} propertyName() : String - + {abstract} propertyName(String value) : void - + {abstract} propertyValue() : Object - + {abstract} propertyValue(Object value) : void - === - This class is used to save data verification error information. -} -interface Validator { - + {abstract} validate(Object object, Class... groups) : Set<ConstraintViolation> - === - Provides the ability to verify that an object complies with a specific constraint. such as non-null, non-empty so on. -} -Validator ..> ConstraintViolation -Validator .right.> ConstraintValidator -ValidationHandler o-- Validator -@enduml -``` - -``` plantuml -@startuml -hide empty members - -skinparam backgroundColor #EEEBDC -skinparam roundcorner 20 -skinparam sequenceArrowThickness 2 -skinparam ClassFontName Consolas - -skinparam class { -BackgroundColor<> LightGray -BackgroundColor<> Pink -} - -annotation Constraint - -interface ConstraintValidator { - + {abstract} initialize(Annotation constraintAnnotation) : void - + {abstract} isValid(T value) : void - === - Represents a constraint validator that validates a specific constraint. - The specific constraint is represented by an annotation. -} - -Constraint .left.> ConstraintValidator - -class NotBlankValidator { - + initialize(NotBlank constraintAnnotation) : void - + isValid(Object value) : boolean -} -NotBlankValidator .up.|> ConstraintValidator -class NotEmptyValidator { - + initialize(NotEmpty constraintAnnotation) : void - + isValid(Object value) : boolean -} -NotEmptyValidator .up.|> ConstraintValidator -class RangeValidator { - + initialize(Range constraintAnnotation) : void - + isValid(Long value) : boolean -} -RangeValidator .up.|> ConstraintValidator - -annotation NotBlank -NotBlank .up.> NotBlankValidator -annotation NotEmpty -NotEmpty .up.> NotEmptyValidator -annotation Range -Range .up.> RangeValidator - -@enduml -``` - -# 核心类 - -### ValidationHandler - -`ValidationHandler`类作为校验能力的入口,通过`AOP`的方式来解析。框架启动时,ValidationHandler类的handle方法会扫描@Validated注解,对有该注解的类或者参数进行解析:如果是类上含有该注解, -则对这个类的所有方法进行判断,判断方法参数是否含有约束注解,如果有,对该方法进行AOP 注入;如果是参数上含有该注解,则对该参数所属的方法进行注入。 - -### ConstraintValidator - -表示约束验证器,对某个特定的约束进行验证。当前实现的`ConstraintValidator`的有: - -- NotBlankValidator: 判断该字符串是否不为`null`,且不是空白字符。 -- NotEmptyValidator:判断该实体是否不为`null`,且不是空对象。 -- RangeValidator:判断该数字是否在所属区间范围内。 - -### ConstraintViolation - -`ConstraintViolation`主要用于保存数据校验的错误信息。当用户使用约束注解进行校验时,如果校验出错,`ConstraintViolation` -里就保存了校验出错的字段、出错原因等信息。通过处理这个异常,可以将错误信息返回给客户端,让其得知请求传递的数据有误,从而进行相应的修正。 - -### 约束注解 - -每个`ConstraintValidator`都有其对应的约束注解供用户使用,如`NotBlankValidator`对应`NotBlank`注解。注解除了特定属性外,都含有`message`、`group`属性 - -- message: 当约束条件不满足时,打印出的异常信息 -- group: - 用于分组约束。通过分组约束可以对校验进行更精确化控制。如果在类级别和方法级别同时使用分组,那么方法级别的分组将覆盖类级别的分组。 - -考虑一下例子: 首先,需要定义一个分组接口: - -``` java -public interface GroupA {} - -public interface GroupB {} -``` - -然后,在需要进行校验的类中,使用`@Validated`注解指定需要校验的分组: - -``` java -public class User { - @NotBlank(message = "用户名不能为空", groups = {GroupA.class}) - private String username; - - @NotBlank(message = "密码不能为空", groups = {GroupB.class}) - private String password; - - // getter and setter -} -``` - -在Controller中,使用`@Validated`注解指定需要校验的分组: - -``` java -public class UserController { - @PostMapping("/login") - public String login(@Validated(GroupA.class) User user) { - // ... - } - - @PostMapping("/register") - public String register(@Validated(GroupB.class) User user) { - // ... - } -} -``` - -这样,在`login`方法中,只会校验`username`字段,而在`register`方法中,只会校验`password`字段。 - diff --git a/framework/fit/java/fit-extension/fit-validation/pom.xml b/framework/fit/java/fit-extension/fit-validation/pom.xml deleted file mode 100644 index 16a8a61ea..000000000 --- a/framework/fit/java/fit-extension/fit-validation/pom.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - 4.0.0 - - - org.fitframework.extension - fit-extension-parent - 3.6.0-SNAPSHOT - - - fit-validation - - FIT Validation - FIT Framework Validation module provides built-in validation functionality. - https://github.com/ModelEngine-Group/fit-framework - - - - - org.fitframework - fit-api - - - org.fitframework - fit-util - - - - - org.fitframework - fit-ioc - test - - - org.junit.jupiter - junit-jupiter - test - - - org.mockito - mockito-core - test - - - org.assertj - assertj-core - test - - - org.fitframework.service - fit-http-classic - test - - - org.fitframework - fit-test-framework - - - diff --git a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ConstraintViolation.java b/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ConstraintViolation.java deleted file mode 100644 index 6d14d8adf..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ConstraintViolation.java +++ /dev/null @@ -1,125 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation; - -import modelengine.fitframework.pattern.builder.BuilderFactory; - -import java.lang.reflect.Method; - -/** - * 表示约束校验失败的数据类。 - * - * @author 邬涨财 - * @since 2023-03-08 - */ -public interface ConstraintViolation { - /** - * 获取校验失败的信息。 - * - * @return 表示校验失败的信息的 {@link String}。 - */ - String message(); - - /** - * 获取校验的属性名。 - * - * @return 表示校验的属性名的 {@link String}。 - */ - String propertyName(); - - /** - * 获取校验的属性值。 - * - * @return 表示校验的属性值的 {@link Object}。 - */ - Object propertyValue(); - - /** - * 获取校验的方法。 - * - * @return 表示校验的方法的 {@link Method}。 - */ - Method validationMethod(); - - /** - * 获取校验注解的参数。 - * - * @return 表示校验注解的参数的 {@link Object}{@code []}。 - */ - Object[] args(); - - /** - * {@link ConstraintViolation} 的构建器。 - */ - interface Builder { - /** - * 向构建器设置校验失败的信息。 - * - * @param message 表示校验失败的信息的 {@link String}。 - * @return 表示构建器的 {@link Builder}。 - */ - Builder message(String message); - - /** - * 向构建器设置校验的属性名。 - * - * @param propertyName 表示校验的属性名的 {@link String}。 - * @return 表示构建器的 {@link Builder}。 - */ - Builder propertyName(String propertyName); - - /** - * 向构建器设置校验的属性值。 - * - * @param propertyValue 表示校验的属性值的 {@link String}。 - * @return 表示构建器的 {@link Builder}。 - */ - Builder propertyValue(Object propertyValue); - - /** - * 向构建器设置校验的方法。 - * - * @param validationMethod 表示校验的方法的 {@link String}。 - * @return 表示构建器的 {@link Builder}。 - */ - Builder validationMethod(Method validationMethod); - - /** - * 向构建器设置校验注解的参数。 - * - * @param args 表示校验注解的参数的 {@link Object}{@code []}。 - * @return 表示构建器的 {@link Builder}。 - */ - Builder args(Object args); - - /** - * 构建对象。 - * - * @return 表示构建出来的对象的 {@link ConstraintViolation}。 - */ - ConstraintViolation build(); - } - - /** - * 获取 {@link ConstraintViolation} 的构建器。 - * - * @return 表示 {@link ConstraintViolation} 的构建器的 {@link Builder}。 - */ - static Builder builder() { - return builder(null); - } - - /** - * 获取 {@link ConstraintViolation} 的构建器,同时将指定对象的值进行填充。 - * - * @param value 表示指定对象的 {@link ConstraintViolation}。 - * @return 表示 {@link ConstraintViolation} 的构建器的 {@link Builder}。 - */ - static Builder builder(ConstraintViolation value) { - return BuilderFactory.get(ConstraintViolation.class, Builder.class).create(value); - } -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java deleted file mode 100644 index 9b9e1cba8..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - */ - -package modelengine.fitframework.validation; - -import modelengine.fitframework.annotation.Component; -import modelengine.fitframework.aop.JoinPoint; -import modelengine.fitframework.aop.annotation.Aspect; -import modelengine.fitframework.aop.annotation.Before; -import modelengine.fitframework.inspection.Validation; -import modelengine.fitframework.ioc.BeanContainer; -import modelengine.fitframework.pattern.builder.BuilderFactory; -import modelengine.fitframework.util.AnnotationUtils; -import modelengine.fitframework.util.ArrayUtils; -import modelengine.fitframework.util.CollectionUtils; -import modelengine.fitframework.util.MapUtils; -import modelengine.fitframework.util.ObjectUtils; -import modelengine.fitframework.util.ReflectionUtils; -import modelengine.fitframework.util.StringUtils; -import modelengine.fitframework.validation.constraints.Constraint; -import modelengine.fitframework.validation.exception.ConstraintViolationException; -import modelengine.fitframework.validation.group.DefaultGroup; -import modelengine.fitframework.value.PropertyValue; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * 校验入口类。 - *

当调用的方法参数包含 {@link Validated} 注解时,会对该方法进行校验处理。当前存在两种场景包含该场景:

- *
    - *
  1. 方法参数直接包含 {@link Validated} 注解,此时校验的是该参数对象的字段。
  2. - *
  3. 方法参数包含约束注解,如 {@link modelengine.fitframework.validation.constraints.NotEmpty},此时校验的是该参数对象。
  4. - *
- * - * @author 邬涨财 - * @since 2023-03-14 - */ -@Aspect -@Component -public class ValidationHandler { - private final BeanContainer container; - private final Map>> validatorMap = - new ConcurrentHashMap<>(); - - /** - * 使用指定的 Bean 容器初始化 {@link ValidationHandler} 的新实例。 - * - * @param container 表示 Bean 容器的 {@link BeanContainer}。 - * @throws IllegalArgumentException 当 {@code container} 为 {@code null} 时。 - */ - public ValidationHandler(BeanContainer container) { - this.container = - Validation.notNull(container, "The bean container cannot be null when construct validation handle."); - } - - @Before(value = "@params(validated)", argNames = "joinPoint, validated") - private void handle(JoinPoint joinPoint, Validated validated) { - Method method = joinPoint.getMethod(); - Object[] args = joinPoint.getArgs(); - List violations = this.handleValidationMethod(method, args) - .stream() - .flatMap(validationMetadata -> this.validate(validationMetadata).stream()) - .collect(Collectors.toList()); - Validation.isTrue(violations.isEmpty(), () -> new ConstraintViolationException(violations)); - } - - private List handleValidationMethod(Method method, Object[] args) { - Class[] classGroups = this.getClassGroups(method); - Parameter[] parameters = ReflectionUtils.getParameters(method); - List validationMetadataList = new ArrayList<>(); - for (int index = 0; index < parameters.length; index++) { - if (this.hasConstraintAnnotation(parameters[index])) { - ValidationMetadata validationMetadata = ValidationMetadata.createValidationParameter(parameters[index], - classGroups, - args[index], - method); - validationMetadataList.add(validationMetadata); - continue; - } - if (this.hasValidatedAnnotation(parameters[index])) { - Class[] validationGroups = this.getValidationGroups(parameters[index], classGroups); - PropertyValue parameterValue = PropertyValue.createParameterValue(parameters[index]); - validationMetadataList.addAll(this.getValidationFields(parameterValue.getParameterizedType(), - args[index], - method, - validationGroups)); - } - } - return validationMetadataList; - } - - private Class[] getClassGroups(Method method) { - return AnnotationUtils.getAnnotation(this.container, method.getDeclaringClass(), Validated.class) - .map(Validated::value) - .filter(ArrayUtils::isNotEmpty) - .orElseGet(() -> new Class[] {DefaultGroup.class}); - } - - private Class[] getValidationGroups(Parameter parameters, Class[] classGroups) { - return AnnotationUtils.getAnnotation(this.container, parameters, Validated.class) - .map(Validated::value) - .filter(ArrayUtils::isNotEmpty) - .orElse(classGroups); - } - - private boolean hasValidatedAnnotation(AnnotatedElement element) { - return AnnotationUtils.getAnnotation(this.container, element, Validated.class).isPresent(); - } - - private boolean hasConstraintAnnotation(AnnotatedElement element) { - return AnnotationUtils.getAnnotation(this.container, element, Constraint.class).isPresent(); - } - - private List getValidationFields(Type validationObject, Object validationValue, Method method, - Class[] validationGroups) { - if (validationObject instanceof ParameterizedType) { - ParameterizedType parameterizedType = ObjectUtils.cast(validationObject); - if (Collection.class.isAssignableFrom(ObjectUtils.cast(parameterizedType.getRawType()))) { - return this.handleCollection(parameterizedType.getActualTypeArguments(), - ObjectUtils.cast(validationValue), - method, - validationGroups); - } - if (Map.class.isAssignableFrom(ObjectUtils.cast(parameterizedType.getRawType()))) { - return this.handleMap(parameterizedType.getActualTypeArguments(), - ObjectUtils.cast(validationValue), - method, - validationGroups); - } - } - if (validationObject instanceof Class) { - Field[] fields = new Field[0]; - Map fieldNameValues = Collections.emptyMap(); - if (!isSimpleClass(ObjectUtils.cast(validationObject))) { - fields = ReflectionUtils.getDeclaredFields(ObjectUtils.cast(validationObject), true); - fieldNameValues = Arrays.stream(fields) - .collect(HashMap::new, - (map, field) -> map.put(field.getName(), - validationValue == null - ? null - : ReflectionUtils.getField(validationValue, field)), - HashMap::putAll); - } - List constraintFieldMetadata = - this.getConstraintFieldMetadata(method, validationGroups, fields, fieldNameValues); - List validatedFieldMetadata = - this.getValidatedFieldMetadata(method, validationGroups, fields, fieldNameValues); - return CollectionUtils.merge(constraintFieldMetadata, validatedFieldMetadata); - } - return Collections.emptyList(); - } - - private List handleCollection(Type[] actualTypeArgs, Collection validationValueCollection, - Method method, Class[] validationGroups) { - Validation.equals(actualTypeArgs.length, 1, "The collection must have exactly 1 parameterized type."); - if (CollectionUtils.isEmpty(validationValueCollection)) { - return Collections.emptyList(); - } - return validationValueCollection.stream() - .flatMap(element -> this.getValidationFields(actualTypeArgs[0], element, method, validationGroups) - .stream()) - .collect(Collectors.toList()); - } - - private List handleMap(Type[] actualTypeArgs, Map validationValueMap, Method method, - Class[] validationGroups) { - Validation.equals(actualTypeArgs.length, 2, "The map must have exactly 2 parameterized types."); - if (MapUtils.isEmpty(validationValueMap)) { - return Collections.emptyList(); - } - return validationValueMap.entrySet() - .stream() - .flatMap(entry -> Stream.concat( - this.getValidationFields(actualTypeArgs[0], entry.getKey(), method, validationGroups).stream(), - this.getValidationFields(actualTypeArgs[1], entry.getValue(), method, validationGroups).stream() - )) - .collect(Collectors.toList()); - } - - private List getConstraintFieldMetadata(Method method, Class[] validationGroups, - Field[] fields, Map fieldNameValues) { - return Arrays.stream(fields) - .filter(this::hasConstraintAnnotation) - .map(field -> ValidationMetadata.createValidationField(field, - validationGroups, - fieldNameValues.get(field.getName()), - method)) - .collect(Collectors.toList()); - } - - private List getValidatedFieldMetadata(Method method, Class[] validationGroups, - Field[] fields, Map fieldNameValues) { - return Arrays.stream(fields) - .filter(this::hasValidatedAnnotation) - .flatMap(field -> this.getValidationFields(PropertyValue.createFieldValue(field).getParameterizedType(), - fieldNameValues.get(field.getName()), - method, - validationGroups).stream()) - .collect(Collectors.toList()); - } - - private List validate(ValidationMetadata validationMetadata) { - List violations = new ArrayList<>(); - for (Annotation annotation : validationMetadata.annotations()) { - if (!this.needValidate(annotation, validationMetadata)) { - continue; - } - this.getConstraintValidators(annotation, validationMetadata) - .stream() - .filter(validator -> !validator.isValid(validationMetadata.value())) - .forEach((validator) -> violations.add(this.buildConstraintViolation(validationMetadata, - annotation, - validator.args()))); - } - return violations; - } - - private List> getConstraintValidators(Annotation annotation, - ValidationMetadata validationMetadata) { - ValidatorKey validatorKey = - ValidatorKey.builder().annotation(annotation).annotatedElement(validationMetadata.element()).build(); - return this.validatorMap.computeIfAbsent(validatorKey, (key) -> this.buildConstraintValidators(annotation)); - } - - private List> buildConstraintValidators(Annotation annotation) { - Class>[] validatorClasses = - AnnotationUtils.getAnnotation(this.container, annotation.annotationType(), Constraint.class) - .orElseThrow(IllegalStateException::new) - .value(); - return Arrays.stream(validatorClasses) - .map(validatorClass -> this.buildConstraintValidator(annotation, validatorClass)) - .collect(Collectors.toList()); - } - - private ConstraintValidator buildConstraintValidator(Annotation annotation, - Class> validatorClass) { - ConstraintValidator validator = - ObjectUtils.cast(ReflectionUtils.instantiate(validatorClass)); - validator.initialize(annotation); - return validator; - } - - private ConstraintViolation buildConstraintViolation(ValidationMetadata validationMetadata, Annotation annotation, - Object[] args) { - String message = - String.valueOf(this.getAnnotationPropertyValue(annotation, "message").orElse(StringUtils.EMPTY)); - return ConstraintViolation.builder() - .message(message) - .propertyName(validationMetadata.name()) - .propertyValue(validationMetadata.value()) - .validationMethod(validationMetadata.getValidationMethod()) - .args(args) - .build(); - } - - /** - * 判断该校验对象是否需要校验,通过比较校验对象的 {@link Validated} 注解和 {@link Constraint} 注解是否有相同的分组。 - *

其中通过校验元数据 {@link ValidationMetadata} 可以获得 {@link Validated} 注解的分组;通过约束注解可以获得 {@link Constraint} - * 上的分组值。

- * - * @param constraintAnnotation 表示约束注解的 {@link Annotation}。 - * @param validationMetadata 表示需要校验的元数据的 {@link ValidationMetadata}。 - * @return 表示是否需要校验的 {@code boolean}。 - */ - private boolean needValidate(Annotation constraintAnnotation, ValidationMetadata validationMetadata) { - if (constraintAnnotation.annotationType().getAnnotation(Constraint.class) == null) { - return false; - } - List> validationClasses = Arrays.asList(validationMetadata.groups()); - Optional optionGroups = this.getAnnotationPropertyValue(constraintAnnotation, "groups"); - if (!optionGroups.isPresent()) { - return validationClasses.contains(DefaultGroup.class); - } - Class[] groups = ObjectUtils.cast(optionGroups.get()); - if (groups.length == 0) { - return validationClasses.contains(DefaultGroup.class); - } - return !CollectionUtils.intersect(validationClasses, Arrays.asList(groups)).isEmpty(); - } - - private Optional getAnnotationPropertyValue(Annotation annotation, String propertyKey) { - Class annotationType = annotation.annotationType(); - try { - Method method = annotationType.getDeclaredMethod(propertyKey); - return Optional.ofNullable(ReflectionUtils.invoke(annotation, method)); - } catch (NoSuchMethodException e) { - return Optional.empty(); - } - } - - private boolean isSimpleClass(Class validationClass) { - return validationClass.isPrimitive() || ReflectionUtils.isPrimitiveWrapper(validationClass) - || validationClass == String.class; - } - - /** - * 表示校验器缓存 {@link #validatorMap} 的键。 - */ - public interface ValidatorKey { - /** - * 获取校验元素的 {@link AnnotatedElement}。 - * - * @return 表示校验元素的 {@link AnnotatedElement}。 - */ - AnnotatedElement annotatedElement(); - - /** - * 获取校验的约束注解的 {@link Annotation}。 - * - * @return 表示校验的约束注解的 {@link Annotation}。 - */ - Annotation annotation(); - - /** - * {@link ValidatorKey} 的构建器。 - */ - interface Builder { - /** - * 向构建器设置校验元素的唯一标识。 - * - * @param annotatedElement 表示设置的校验元素的唯一标识的 {@link String}。 - * @return 表示构建器的 {@link Builder}。 - */ - Builder annotatedElement(AnnotatedElement annotatedElement); - - /** - * 向构建器设置校验的约束注解。 - * - * @param annotation 表示设置的校验约束注解的 {@link Annotation}。 - * @return 表示构建器的 {@link Builder}。 - */ - Builder annotation(Annotation annotation); - - /** - * 构建对象。 - * - * @return 表示构建出来的对象的 {@link }。 - */ - ValidatorKey build(); - } - - /** - * 获取 {@link ValidatorKey} 的构建器。 - * - * @return 表示 {@link ValidatorKey} 的构建器的 {@link Builder}。 - */ - static Builder builder() { - return builder(null); - } - - /** - * 获取 {@link ValidatorKey} 的构建器,同时将指定对象的值进行填充。 - * - * @param value 表示指定对象的 {@link ValidatorKey}。 - * @return 表示 {@link ValidatorKey} 的构建器的 {@link Builder}。 - */ - static Builder builder(ValidatorKey value) { - return BuilderFactory.get(ValidatorKey.class, Builder.class).create(value); - } - } -} \ No newline at end of file diff --git a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ValidationMetadata.java b/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ValidationMetadata.java deleted file mode 100644 index 19968db70..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/ValidationMetadata.java +++ /dev/null @@ -1,95 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation; - -import modelengine.fitframework.validation.domain.ValidationField; -import modelengine.fitframework.validation.domain.ValidationParameter; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; - -/** - * 表示校验的元数据。 - * - * @author 白鹏坤 - * @author 邬涨财 - * @since 2023-04-23 - */ -public interface ValidationMetadata { - /** - * 获取分组信息。 - * - * @return 表示分组信息集合的 {@link Class}{@code []}。 - */ - Class[] groups(); - - /** - * 获取校验元素的属性值。 - * - * @return 表示校验元素的属性值的 {@link Object}。 - */ - Object value(); - - /** - * 获取校验的方法。 - * - * @return 表示校验方法的 {@link Method}。 - */ - Method getValidationMethod(); - - /** - * 获取校验的元素。 - * - * @return 表示校验的元素 {@link AnnotatedElement}。 - */ - AnnotatedElement element(); - - /** - * 获取校验元素的属性名。 - * - * @return 表示校验的元素的属性名的 {@link String}。 - */ - String name(); - - /** - * 获取校验元素的所有注解。 - * - * @return 表示校验元素的所有注解的 {@link Annotation}{@code []}。 - */ - Annotation[] annotations(); - - /** - * 创建一个 {@link ValidationMetadata} 对象,表示需要校验的字段的元数据。 - * - * @param field 表示需要校验的字段的 {@link Field}。 - * @param groups 表示需要校验的分组的 {@link Class}{@code []}。 - * @param value 表示字段值的 {@link Object}。 - * @param validationMethod 表示校验的方法的 {@link Method}. - * @return 表示创建后的校验元数据的 {@link ValidationMetadata}。 - */ - static ValidationMetadata createValidationField(Field field, Class[] groups, Object value, - Method validationMethod) { - return new ValidationField(field, groups, value, validationMethod); - } - - /** - * 创建一个 {@link ValidationMetadata} 对象,表示需要校验的参数的元数据。 - * - * @param parameter 表示需要校验的参数的 {@link Parameter}。 - * @param groups 表示需要校验的分组的 {@link Class}{@code []}。 - * @param value 表示参数值的 {@link Object}。 - * @param validationMethod 表示校验的方法的 {@link Method}. - * @return 表示创建后的校验元数据的 {@link ValidationMetadata}。 - */ - static ValidationMetadata createValidationParameter(Parameter parameter, Class[] groups, Object value, - Method validationMethod) { - return new ValidationParameter(parameter, groups, value, validationMethod); - } -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/AbstractValidationMetadata.java b/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/AbstractValidationMetadata.java deleted file mode 100644 index bc9647278..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/AbstractValidationMetadata.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - */ - -package modelengine.fitframework.validation.domain; - -import modelengine.fitframework.inspection.Validation; -import modelengine.fitframework.validation.ValidationMetadata; - -import java.lang.reflect.Method; - -/** - * 表示 {@link ValidationMetadata} 的抽象实现。 - * - * @author 白鹏坤 - * @author 邬涨财 - * @since 2023-04-23 - */ -public abstract class AbstractValidationMetadata implements ValidationMetadata { - private final Class[] groups; - private final Object value; - private final Method validationMethod; - - /** - * 使用指定的分组、值和验证方法初始化 {@link AbstractValidationMetadata} 的新实例。 - * - * @param groups 表示分组的 {@link Class}{@code []}。 - * @param value 表示值的 {@link Object}。 - * @param validationMethod 表示验证方法的 {@link Method}。 - * @throws IllegalArgumentException 当 {@code groups} 或 {@code validationMethod} 为 {@code null} 时。 - */ - public AbstractValidationMetadata(Class[] groups, Object value, Method validationMethod) { - this.groups = Validation.notNull(groups, "The groups cannot be null when construct validation metadata."); - this.value = value; - this.validationMethod = Validation.notNull(validationMethod, - "The validation method cannot be null when construct validation metadata."); - } - - @Override - public Class[] groups() { - return this.groups; - } - - @Override - public Object value() { - return this.value; - } - - @Override - public Method getValidationMethod() { - return this.validationMethod; - } -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/ValidationField.java b/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/ValidationField.java deleted file mode 100644 index 4dbf933f7..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/ValidationField.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - */ - -package modelengine.fitframework.validation.domain; - -import modelengine.fitframework.inspection.Validation; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * 校验类型为字段的元数据类。 - * - * @author 邬涨财 - * @since 2023-05-18 - */ -public class ValidationField extends AbstractValidationMetadata { - private final Field field; - - /** - * 使用指定的字段、分组、值和验证方法初始化 {@link ValidationField} 的新实例。 - * - * @param field 表示字段的 {@link Field}。 - * @param groups 表示分组的 {@link Class}{@code []}。 - * @param value 表示值的 {@link Object}。 - * @param validationMethod 表示验证方法的 {@link Method}。 - * @throws IllegalArgumentException 当 {@code field}、{@code groups} 或 {@code validationMethod} 为 {@code null} 时。 - */ - public ValidationField(Field field, Class[] groups, Object value, Method validationMethod) { - super(groups, value, validationMethod); - this.field = Validation.notNull(field, "The field cannot be null when construct validation filed."); - } - - @Override - public AnnotatedElement element() { - return this.field; - } - - @Override - public String name() { - return this.field.getName(); - } - - @Override - public Annotation[] annotations() { - return this.field.getAnnotations(); - } -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/ValidationParameter.java b/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/ValidationParameter.java deleted file mode 100644 index 6982e06d7..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/domain/ValidationParameter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - */ - -package modelengine.fitframework.validation.domain; - -import modelengine.fitframework.inspection.Validation; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; - -/** - * 校验类型为参数的元数据类。 - * - * @author 邬涨财 - * @since 2023-05-19 - */ -public class ValidationParameter extends AbstractValidationMetadata { - private final Parameter parameter; - - /** - * 使用指定的参数、分组、值和验证方法初始化 {@link ValidationParameter} 的新实例。 - * - * @param parameter 表示参数的 {@link Parameter}。 - * @param groups 表示分组的 {@link Class}{@code []}。 - * @param value 表示值的 {@link Object}。 - * @param validationMethod 表示校验方法的 {@link Method}。 - * @throws IllegalArgumentException 当 {@code parameter}、{@code groups} 或 {@code validationMethod} 为 {@code null} 时。 - */ - public ValidationParameter(Parameter parameter, Class[] groups, Object value, Method validationMethod) { - super(groups, value, validationMethod); - this.parameter = - Validation.notNull(parameter, "The parameter cannot be null when construct validation parameter."); - } - - @Override - public AnnotatedElement element() { - return this.parameter; - } - - @Override - public String name() { - return this.parameter.getName(); - } - - @Override - public Annotation[] annotations() { - return this.parameter.getAnnotations(); - } -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/exception/ConstraintViolationException.java b/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/exception/ConstraintViolationException.java deleted file mode 100644 index 0c1b19f48..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/exception/ConstraintViolationException.java +++ /dev/null @@ -1,67 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.exception; - -import static modelengine.fitframework.util.ObjectUtils.nullIf; - -import modelengine.fitframework.util.CollectionUtils; -import modelengine.fitframework.util.StringUtils; -import modelengine.fitframework.validation.ConstraintViolation; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -/** - * 表示校验失败的异常。 - * - * @author 邬涨财 - * @since 2023-05-18 - */ -public class ConstraintViolationException extends RuntimeException { - private final List violations; - - /** - * 表示创建一个 {@link ConstraintViolationException} 的新实例。 - * - * @param message 表示异常消息的 {@link String}。 - * @param violations 表示约束校验失败的数据类列表的 {@link List}{@code <}{@link ConstraintViolation}{@code >}。 - */ - public ConstraintViolationException(String message, List violations) { - super(message); - this.violations = nullIf(violations, Collections.emptyList()); - } - - /** - * 表示创建一个 {@link ConstraintViolationException} 的新实例。 - * - * @param violations 表示约束校验失败的数据类列表的 {@link List}{@code <}{@link ConstraintViolation}{@code >}。 - */ - public ConstraintViolationException(List violations) { - this(buildMessage(violations), violations); - } - - private static String buildMessage(List violations) { - if (CollectionUtils.isEmpty(violations)) { - return StringUtils.EMPTY; - } - return violations.stream() - .filter(Objects::nonNull) - .map(ConstraintViolation::message) - .collect(Collectors.joining(", ")); - } - - /** - * 获取约束校验失败的数据类列表信息。 - * - * @return 表示约束校验失败的数据类列表信息的 {@link List}{@code <}{@link ConstraintViolation}{@code >}。 - */ - public List getViolations() { - return this.violations; - } -} \ No newline at end of file diff --git a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/group/DefaultGroup.java b/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/group/DefaultGroup.java deleted file mode 100644 index 4bfe62c9c..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/main/java/modelengine/fitframework/validation/group/DefaultGroup.java +++ /dev/null @@ -1,15 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.group; - -/** - * 默认分组。group 为空时,使用默认分组。 - * - * @author 白鹏坤 - * @since 2023-04-23 - */ -public interface DefaultGroup {} diff --git a/framework/fit/java/fit-extension/fit-validation/src/main/resources/application.yaml b/framework/fit/java/fit-extension/fit-validation/src/main/resources/application.yaml deleted file mode 100644 index f9de2211d..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/main/resources/application.yaml +++ /dev/null @@ -1,4 +0,0 @@ -fit: - beans: - packages: - - 'modelengine.fitframework.validation' diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java deleted file mode 100644 index 8d70066e7..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation; - -import static org.assertj.core.api.Assertions.assertThat; - -import modelengine.fit.http.client.HttpClassicClientResponse; -import modelengine.fitframework.annotation.Fit; -import modelengine.fitframework.test.annotation.MvcTest; -import modelengine.fitframework.test.domain.mvc.MockMvc; -import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; -import modelengine.fitframework.test.domain.mvc.request.MockRequestBuilder; -import modelengine.fitframework.validation.data.Car; -import modelengine.fitframework.validation.data.Product; -import modelengine.fitframework.validation.data.ValidationDataController; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; - -/** - * {@link ValidationDataController} 的测试集。 - * - * @author 吕博文 - * @since 2024-08-15 - */ -@MvcTest(classes = {ValidationDataController.class}) -@DisplayName("测试 EvalDataController") -public class ValidationDataControllerTest { - @Fit - private MockMvc mockMvc; - - private HttpClassicClientResponse response; - - @AfterEach - void teardown() throws IOException { - if (this.response != null) { - this.response.close(); - } - } - - @Test - @DisplayName("合法 Car 对象校验") - void shouldOKWhenCreateValidCar() { - Car validCar = new Car(1, 1, "brand", "model", -1, -1); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/car/default").jsonEntity(validCar).responseType(Void.class); - this.response = this.mockMvc.perform(requestBuilder); - assertThat(this.response.statusCode()).isEqualTo(200); - } - - @Test - @DisplayName("不合法 Car 对象校验") - void shouldFailedWhenCreateInvalidCar() { - Car invalidCar = new Car(0, 3, "", "abd", -1, -1); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/car/default").jsonEntity(invalidCar).responseType(Void.class); - this.response = this.mockMvc.perform(requestBuilder); - assertThat(this.response.statusCode()).isEqualTo(500); - } - - @Test - @DisplayName("自定义分组校验 Car 对象") - void shouldOKWhenCreateValidCarWithCarGroup() { - Car invalidCar = new Car(0, 2, "", "abd", 2000, -1); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/car/carGroup").jsonEntity(invalidCar).responseType(Void.class); - this.response = this.mockMvc.perform(requestBuilder); - assertThat(this.response.statusCode()).isEqualTo(200); - } - - @Test - @DisplayName("自定义分组校验 Car 对象") - void shouldFailedWhenCreateInvalidCarWithCarGroup() { - Car invalidCar = new Car(0, 3, "", "abd", -1, -1); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/car/carGroup").jsonEntity(invalidCar).responseType(Void.class); - this.response = this.mockMvc.perform(requestBuilder); - assertThat(this.response.statusCode()).isEqualTo(500); - } - - @Test - @DisplayName("合法 Product 对象校验") - void shouldOKWhenCreateValidProduct() { - Product product = new Product("mac", 10499.0, 100, "computer"); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/product/default").jsonEntity(product).responseType(Void.class); - this.response = this.mockMvc.perform(requestBuilder); - assertThat(this.response.statusCode()).isEqualTo(200); - } - - @Test - @DisplayName("不合法 Product 对象校验") - void shouldFailedWhenCreateInvalidProduct() { - Product product = new Product("", 10499.0, -1, "computer"); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/product/default").jsonEntity(product).responseType(Void.class); - this.response = this.mockMvc.perform(requestBuilder); - assertThat(this.response.statusCode()).isEqualTo(500); - } - - @Test - @DisplayName("合法 Product-List 对象校验: cars == null") - void shouldOkWhenCreateInvalidProductWithNoCar() { - Product product = new Product("mac", 10499.0, 100, "computer", null); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/product/default").jsonEntity(product).responseType(Void.class); - this.response = this.mockMvc.perform(requestBuilder); - assertThat(this.response.statusCode()).isEqualTo(200); - } - - @Test - @DisplayName("合法 Product-List 对象校验: cars.size() == 1") - void shouldOkWhenCreateInvalidProductWith1Car() { - Car validCar = new Car(1, 1, "brand", "model", 2000, 1999); - Product product = new Product("mac", 10499.0, 100, "computer", Collections.singletonList(validCar)); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/product/default").jsonEntity(product).responseType(Void.class); - this.response = this.mockMvc.perform(requestBuilder); - assertThat(this.response.statusCode()).isEqualTo(200); - } - - @Test - @DisplayName("不合法 Product-List 对象校验: cars.size() == 2") - void shouldFailedWhenCreateInvalidProductWith2Cars() { - Car validCar = new Car(1, 1, "brand", "model", 2000, 1999); - Product product = new Product("mac", 10499.0, 100, "computer", Arrays.asList(validCar, validCar)); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/product/default").jsonEntity(product).responseType(Void.class); - this.response = this.mockMvc.perform(requestBuilder); - assertThat(this.response.statusCode()).isEqualTo(500); - } -} \ No newline at end of file diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java deleted file mode 100644 index 130e05803..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ /dev/null @@ -1,489 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowableOfType; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import modelengine.fitframework.aop.JoinPoint; -import modelengine.fitframework.ioc.BeanContainer; -import modelengine.fitframework.ioc.annotation.AnnotationMetadataResolver; -import modelengine.fitframework.ioc.annotation.support.DefaultAnnotationMetadataResolver; -import modelengine.fitframework.runtime.FitRuntime; -import modelengine.fitframework.util.ObjectUtils; -import modelengine.fitframework.util.ReflectionUtils; -import modelengine.fitframework.validation.data.Car; -import modelengine.fitframework.validation.data.CarValidate; -import modelengine.fitframework.validation.data.Company; -import modelengine.fitframework.validation.data.NestedValidate; -import modelengine.fitframework.validation.data.Product; -import modelengine.fitframework.validation.data.ProductValidate; -import modelengine.fitframework.validation.data.StudentValidate; -import modelengine.fitframework.validation.exception.ConstraintViolationException; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** - * {@link ValidationHandler} 的单元测试。 - * - * @author 邬涨财 - * @since 2023-05-23 - */ -public class ValidationHandlerTest { - private final BeanContainer beanContainer = mock(BeanContainer.class); - private final FitRuntime fitRuntime = mock(FitRuntime.class); - private final AnnotationMetadataResolver annotationMetadataResolver = new DefaultAnnotationMetadataResolver(); - private final Validated validated = Mockito.mock(Validated.class); - private final ValidationHandler handler = new ValidationHandler(beanContainer); - - @Nested - @DisplayName("使用默认的分组进行校验") - class UseDefaultGroupTest { - @BeforeEach - void setUp() { - when(validated.value()).thenReturn(new Class[0]); - when(fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); - when(beanContainer.runtime()).thenReturn(fitRuntime); - } - - /** - * 调用 {@link CarValidate#validate1(Car)} 作为需要校验的方法。 - */ - @Test - @DisplayName("校验数据类,该数据类的 Constraint 字段会被校验,其余字段不会被校验") - public void givenFieldsWithConstraintAnnotationThenValidateHappened() { - // when - Method validateMethod = ReflectionUtils.getDeclaredMethod(CarValidate.class, "validate1", Car.class); - Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, - "handle", - JoinPoint.class, - Validated.class); - Car car = new Car(10, 10, "", "", -1, -1); - handleValidatedMethod.setAccessible(true); - JoinPoint joinPoint = mock(JoinPoint.class); - when(joinPoint.getMethod()).thenReturn(validateMethod); - when(joinPoint.getArgs()).thenReturn(new Object[] {car}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - assertThat(expectedException.getMessage()).isEqualTo("座位数量范围只能在0和6!, 发动机数量范围只能在0和2!, 品牌不能为空!, 型号不能为空!"); - } - - /** - * 调用 {@link ProductValidate#validate1(Product)} 作为需要校验的方法。 - */ - @Test - @DisplayName("校验数据类,该数据类的 Constraint 字段会被校验,其余字段不会被校验") - void givenFieldsWithConstraintAnnotationThenValidateHappened2() { - // when - Method validateMethod = - ReflectionUtils.getDeclaredMethod(ProductValidate.class, "validate1", Product.class); - Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, - "handle", - JoinPoint.class, - Validated.class); - Product product = new Product("computer", -1.0, 100, " "); - handleValidatedMethod.setAccessible(true); - JoinPoint joinPoint = mock(JoinPoint.class); - when(joinPoint.getMethod()).thenReturn(validateMethod); - when(joinPoint.getArgs()).thenReturn(new Object[] {product}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - assertThat(expectedException.getMessage()).isEqualTo("产品价格必须为正, 产品类别不能为空"); - } - - /** - * 调用 {@link ProductValidate#validate1(Product)} 作为需要校验的方法。 - */ - @Test - @DisplayName("校验数据类,该数据类的 Constraint 字段会被校验,其余字段不会被校验") - void givenFieldsWithConstraintAnnotationThenValidateHappened3() { - // when - Method validateMethod = - ReflectionUtils.getDeclaredMethod(ProductValidate.class, "validate1", Product.class); - Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, - "handle", - JoinPoint.class, - Validated.class); - Product product = new Product(null, 12999.0, null, "electronic devices"); - handleValidatedMethod.setAccessible(true); - JoinPoint joinPoint = mock(JoinPoint.class); - when(joinPoint.getMethod()).thenReturn(validateMethod); - when(joinPoint.getArgs()).thenReturn(new Object[] {product}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - assertThat(expectedException.getMessage()).isEqualTo("产品名不能为空, 产品数量必须为正"); - } - - /** - * 调用 {@link CarValidate#validate2(int, int)} 作为需要校验的方法。 - */ - @Test - @DisplayName("校验方法参数,该方法的 Constraint 参数会被校验,其余参数不会被校验") - public void givenParametersWithConstraintAnnotationThenValidateHappened() { - // when - Method validateMethod = - ReflectionUtils.getDeclaredMethod(CarValidate.class, "validate2", int.class, int.class); - Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, - "handle", - JoinPoint.class, - Validated.class); - handleValidatedMethod.setAccessible(true); - JoinPoint joinPoint = mock(JoinPoint.class); - when(joinPoint.getMethod()).thenReturn(validateMethod); - when(joinPoint.getArgs()).thenReturn(new Object[] {-1, -1}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - assertThat(expectedException.getMessage()).isEqualTo("座位数量范围只能在0和6!"); - } - } - - @Nested - @DisplayName("使用自定义的分组进行校验") - class UseCustomGroupTest { - @BeforeEach - void setUp() { - when(validated.value()).thenReturn(new Class[0]); - when(fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); - when(beanContainer.runtime()).thenReturn(fitRuntime); - } - - /** - * 调用 {@link CarValidate#validate3(Car)} 作为需要校验的方法。 - */ - @Test - @DisplayName("校验数据类,只会校验与数据类的分组一致的字段分组。") - public void givenFieldsThenSameGroupValidateHappened() { - // when - Method validateMethod = ReflectionUtils.getDeclaredMethod(CarValidate.class, "validate3", Car.class); - Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, - "handle", - JoinPoint.class, - Validated.class); - Car car = new Car(10, 10, "", "", -1, -1); - handleValidatedMethod.setAccessible(true); - JoinPoint joinPoint = mock(JoinPoint.class); - when(joinPoint.getMethod()).thenReturn(validateMethod); - when(joinPoint.getArgs()).thenReturn(new Object[] {car}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - assertThat(expectedException.getMessage()).isEqualTo("生产年份在2000-2030之内"); - } - - /** - * 调用 {@link StudentValidate#validateStudent(int)} 作为需要校验的方法。 - */ - @Test - @DisplayName("校验方法参数,只会校验与数据类的分组一致的方法参数。") - public void givenParametersThenSameGroupValidateHappened() { - // when - Method validateMethod = - ReflectionUtils.getDeclaredMethod(StudentValidate.class, "validateStudent", int.class); - Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, - "handle", - JoinPoint.class, - Validated.class); - handleValidatedMethod.setAccessible(true); - JoinPoint joinPoint = mock(JoinPoint.class); - when(joinPoint.getMethod()).thenReturn(validateMethod); - when(joinPoint.getArgs()).thenReturn(new Object[] {-1}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - assertThat(expectedException.getMessage()).isEqualTo("范围要在7~20之内"); - } - - /** - * 调用 {@link StudentValidate#validateTeacher(int)} 作为需要校验的方法。 - */ - @Test - @DisplayName("校验方法参数,与数据类的分组不一致的方法参数不会校验。") - public void givenParametersThenDifferentGroupValidateNotHappened() { - // when - Method validateMethod = - ReflectionUtils.getDeclaredMethod(StudentValidate.class, "validateTeacher", int.class); - Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, - "handle", - JoinPoint.class, - Validated.class); - handleValidatedMethod.setAccessible(true); - JoinPoint joinPoint = mock(JoinPoint.class); - when(joinPoint.getMethod()).thenReturn(validateMethod); - when(joinPoint.getArgs()).thenReturn(new Object[] {-1}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); - - // then - assertThat(invocationTargetException == null).isTrue(); - } - } - - @Nested - @DisplayName("测试嵌套校验") - class NestedTest { - private static final String INVALID_CAR1_MSG = "座位数量范围只能在0和6!, 品牌不能为空!"; - private static final String INVALID_CAR2_MSG = "型号不能为空!"; - private static final String INVALID_PRODUCT1_MSG = "产品名不能为空, 产品数量必须为正"; - private static final String INVALID_PRODUCT2_MSG = "产品类别不能为空"; - - private final Car validCar = new Car(5, 1, "brand", "model", 2024, 1999); - private final Car invalidCar1 = new Car(-1, 1, "", "model", 2024, 1999); - private final Car invalidCar2 = new Car(5, 1, "brand", "", 2024, 1999); - private final Product validProduct = new Product("name", 1.0, 1, "category"); - private final Product invalidProduct1 = new Product("", 1.0, -1, "category"); - private final Product invalidProduct2 = new Product("name", 1.0, 1, ""); - private final Method handleValidatedMethod = - ReflectionUtils.getDeclaredMethod(ValidationHandler.class, "handle", JoinPoint.class, Validated.class); - private final JoinPoint joinPoint = mock(JoinPoint.class); - - @BeforeEach - void setUp() { - when(validated.value()).thenReturn(new Class[0]); - when(fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); - when(beanContainer.runtime()).thenReturn(fitRuntime); - handleValidatedMethod.setAccessible(true); - } - - @Test - @DisplayName("测试嵌套校验类 Company") - void shouldReturnMsgWhenValidateCompany() { - Method validateMethod = ReflectionUtils.getDeclaredMethod(NestedValidate.class, "test1", Company.class); - when(this.joinPoint.getMethod()).thenReturn(validateMethod); - Company company = - new Company(-1, 100, this.invalidProduct2, Arrays.asList(this.invalidCar1, this.invalidCar2)); - when(this.joinPoint.getArgs()).thenReturn(new Object[] {company}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, this.joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - List msgList = - Arrays.asList("经理只能有0-1个!", INVALID_PRODUCT2_MSG, INVALID_CAR1_MSG, INVALID_CAR2_MSG); - assertThat(expectedException.getMessage()).isEqualTo(String.join(", ", msgList)); - } - - @Test - @DisplayName("测试 @Validated List") - void shouldReturnMsgWhenValidateList() { - Method validateMethod = ReflectionUtils.getDeclaredMethod(NestedValidate.class, "test2", List.class); - when(this.joinPoint.getMethod()).thenReturn(validateMethod); - when(this.joinPoint.getArgs()).thenReturn(new Object[] { - Arrays.asList(this.validCar, this.invalidCar1, this.invalidCar2) - }); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, this.joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - List msgList = Arrays.asList(INVALID_CAR1_MSG, INVALID_CAR2_MSG); - assertThat(expectedException.getMessage()).isEqualTo(String.join(", ", msgList)); - } - - @Test - @DisplayName("测试 @Validated List>") - void shouldReturnMsgWhenValidateListInList() { - Method validateMethod = ReflectionUtils.getDeclaredMethod(NestedValidate.class, "test3", List.class); - when(this.joinPoint.getMethod()).thenReturn(validateMethod); - List personList1 = Arrays.asList(this.validCar, this.invalidCar1, this.invalidCar2); - List personList2 = Arrays.asList(this.validCar, this.invalidCar1); - - when(this.joinPoint.getArgs()).thenReturn(new Object[] {Arrays.asList(personList1, personList2)}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, this.joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - List msgList = Arrays.asList(INVALID_CAR1_MSG, INVALID_CAR2_MSG, INVALID_CAR1_MSG); - assertThat(expectedException.getMessage()).isEqualTo(String.join(", ", msgList)); - } - - @Test - @DisplayName("测试 @Validated Map") - void shouldReturnMsgWhenValidateMapSimple() { - Method validateMethod = ReflectionUtils.getDeclaredMethod(NestedValidate.class, "test4", Map.class); - when(this.joinPoint.getMethod()).thenReturn(validateMethod); - LinkedHashMap map = new LinkedHashMap<>(); - map.put("1", this.validCar); - map.put("2", this.invalidCar1); - map.put("3", this.invalidCar2); - - when(this.joinPoint.getArgs()).thenReturn(new Object[] {map}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, this.joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - List msgList = Arrays.asList(INVALID_CAR1_MSG, INVALID_CAR2_MSG); - assertThat(expectedException.getMessage()).isEqualTo(String.join(", ", msgList)); - } - - @Test - @DisplayName("测试 @Validated Map") - void shouldReturnMsgWhenValidateMapObj() { - Method validateMethod = ReflectionUtils.getDeclaredMethod(NestedValidate.class, "test5", Map.class); - when(this.joinPoint.getMethod()).thenReturn(validateMethod); - LinkedHashMap map = new LinkedHashMap<>(); - map.put(this.validCar, this.validProduct); - map.put(this.invalidCar1, this.invalidProduct1); - map.put(this.invalidCar2, this.invalidProduct2); - - when(this.joinPoint.getArgs()).thenReturn(new Object[] {map}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, this.joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - List msgList = - Arrays.asList(INVALID_CAR1_MSG, INVALID_PRODUCT1_MSG, INVALID_CAR2_MSG, INVALID_PRODUCT2_MSG); - assertThat(expectedException.getMessage()).isEqualTo(String.join(", ", msgList)); - } - - @Test - @DisplayName("测试 @Validated Map>") - void shouldReturnMsgWhenValidateMapInMap() { - Method validateMethod = ReflectionUtils.getDeclaredMethod(NestedValidate.class, "test6", Map.class); - - when(this.joinPoint.getMethod()).thenReturn(validateMethod); - LinkedHashMap map1 = new LinkedHashMap<>(); - map1.put(this.validCar, this.invalidProduct1); - map1.put(this.invalidCar1, this.validProduct); - map1.put(this.invalidCar2, this.invalidProduct2); - LinkedHashMap map2 = new LinkedHashMap<>(); - map2.put(this.invalidCar1, this.invalidProduct1); - map2.put(this.validCar, this.validProduct); - LinkedHashMap> nestMap = new LinkedHashMap<>(); - nestMap.put(this.validCar, map1); - nestMap.put(this.invalidCar1, map2); - - when(this.joinPoint.getArgs()).thenReturn(new Object[] {nestMap}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, this.joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - List msgList = Arrays.asList(INVALID_PRODUCT1_MSG, - INVALID_CAR1_MSG, - INVALID_CAR2_MSG, - INVALID_PRODUCT2_MSG, - INVALID_CAR1_MSG, - INVALID_CAR1_MSG, - INVALID_PRODUCT1_MSG); - assertThat(expectedException.getMessage()).isEqualTo(String.join(", ", msgList)); - } - - @Test - @DisplayName("测试 @Validated List>") - void shouldReturnMsgWhenValidateMapInCar() { - Method validateMethod = ReflectionUtils.getDeclaredMethod(NestedValidate.class, "test7", List.class); - when(this.joinPoint.getMethod()).thenReturn(validateMethod); - LinkedHashMap map1 = new LinkedHashMap<>(); - map1.put(this.validCar, this.invalidProduct1); - map1.put(this.invalidCar1, this.validProduct); - map1.put(this.invalidCar2, this.invalidProduct2); - LinkedHashMap map2 = new LinkedHashMap<>(); - map2.put(this.invalidCar1, this.invalidProduct1); - map2.put(this.validCar, this.validProduct); - - when(this.joinPoint.getArgs()).thenReturn(new Object[] {Arrays.asList(map1, map2)}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, this.joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - List msgList = Arrays.asList(INVALID_PRODUCT1_MSG, - INVALID_CAR1_MSG, - INVALID_CAR2_MSG, - INVALID_PRODUCT2_MSG, - INVALID_CAR1_MSG, - INVALID_PRODUCT1_MSG); - assertThat(expectedException.getMessage()).isEqualTo(String.join(", ", msgList)); - } - - @Test - @DisplayName("测试 @Validated Map>") - void shouldReturnMsgWhenValidateListInMap() { - Method validateMethod = ReflectionUtils.getDeclaredMethod(NestedValidate.class, "test8", Map.class); - when(this.joinPoint.getMethod()).thenReturn(validateMethod); - List productList1 = Arrays.asList(this.validProduct, this.invalidProduct1); - List productList2 = Arrays.asList(this.validProduct, this.invalidProduct2); - LinkedHashMap> map = new LinkedHashMap<>(); - map.put(this.invalidCar1, productList1); - map.put(this.invalidCar2, productList2); - - when(this.joinPoint.getArgs()).thenReturn(new Object[] {map}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, this.joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - List msgList = - Arrays.asList(INVALID_CAR1_MSG, INVALID_PRODUCT1_MSG, INVALID_CAR2_MSG, INVALID_PRODUCT2_MSG); - assertThat(expectedException.getMessage()).isEqualTo(String.join(", ", msgList)); - } - - @Test - @DisplayName("测试 @Validated List") - void shouldReturnMsgWhenValidateListComplex() { - Method validateMethod = ReflectionUtils.getDeclaredMethod(NestedValidate.class, "test9", List.class); - when(this.joinPoint.getMethod()).thenReturn(validateMethod); - Company company = - new Company(-1, 100, this.validProduct, Arrays.asList(this.invalidCar1, this.invalidCar2)); - when(this.joinPoint.getArgs()).thenReturn(new Object[] {List.of(company)}); - InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, this.joinPoint, validated)); - - // then - ConstraintViolationException expectedException = - ObjectUtils.cast(invocationTargetException.getTargetException()); - List msgList = Arrays.asList("经理只能有0-1个!", INVALID_CAR1_MSG, INVALID_CAR2_MSG); - assertThat(expectedException.getMessage()).isEqualTo(String.join(", ", msgList)); - } - } -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/annotation/MaxSize.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/annotation/MaxSize.java deleted file mode 100644 index c0d97f0bb..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/annotation/MaxSize.java +++ /dev/null @@ -1,46 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.annotation; - -import modelengine.fitframework.validation.Validated; -import modelengine.fitframework.validation.constraints.Constraint; -import modelengine.fitframework.validation.validator.MaxSizeValidator; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * 表示集合元素数量限制的测试注解类。 - * - * @author 李金绪 - * @since 2025-03-17 - */ -@Retention(RetentionPolicy.RUNTIME) -@Constraint({MaxSizeValidator.class}) -@Validated -public @interface MaxSize { - /** - * 表示集合元素的大小的上限值。 - * - * @return 表示集合元素的大小的上限值的 {@code long}。 - */ - long max(); - - /** - * 表示校验失败的信息。 - * - * @return 表示校验失败的信息的 {@link String}。 - */ - String message() default "must be lesser than the max value."; - - /** - * 表示校验的分组。 - * - * @return 表示校验分组的 {@link Class}{@code []}。 - */ - Class[] groups() default {}; -} \ No newline at end of file diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Car.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Car.java deleted file mode 100644 index 092ed1c7b..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Car.java +++ /dev/null @@ -1,63 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fitframework.validation.constraints.NotBlank; -import modelengine.fitframework.validation.constraints.NotEmpty; -import modelengine.fitframework.validation.constraints.Range; -import modelengine.fitframework.validation.group.NormalCarGroup; -import modelengine.fitframework.validation.group.OldCarGroup; - -/** - * 表示汽车的数据类。 - * - * @author 李金绪 - * @since 2024-09-04 - */ -public class Car { - @Range(min = 0, max = 6, message = "座位数量范围只能在0和6!") - private int seats; - - @Range(min = 0, max = 2, message = "发动机数量范围只能在0和2!") - private int engines; - - @NotBlank(message = "品牌不能为空!") - private String brand; - - @NotEmpty(message = "型号不能为空!") - private String model; - - @Range(min = 2000, max = 2030, message = "生产年份在2000-2030之内", groups = {NormalCarGroup.class}) - private int normalManufactureYear; - - @Range(min = 1900, max = 1999, message = "生产年份在1900-1999之内", groups = {OldCarGroup.class}) - private int oldManufactureYear; - - /** - * 表示创建一个 {@link Car} 的新实例。 - */ - public Car() {} - - /** - * 表示创建一个 {@link Car} 的新实例。 - * - * @param seats 表示座位数量的 {@code int}。 - * @param engines 表示发动机数量的 {@code int}。 - * @param brand 表示品牌的 {@link String}。 - * @param model 表示型号的 {@link String}。 - * @param normalManufactureYear 表示新型汽车的生产年份的 {@code int}。 - * @param oldManufactureYear 表示老旧汽车的生产年份的 {@code int}。 - */ - public Car(int seats, int engines, String brand, String model, int normalManufactureYear, int oldManufactureYear) { - this.seats = seats; - this.engines = engines; - this.brand = brand; - this.model = model; - this.normalManufactureYear = normalManufactureYear; - this.oldManufactureYear = oldManufactureYear; - } -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/CarValidate.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/CarValidate.java deleted file mode 100644 index f0b389fe3..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/CarValidate.java +++ /dev/null @@ -1,42 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fitframework.validation.Validated; -import modelengine.fitframework.validation.constraints.Range; -import modelengine.fitframework.validation.group.NormalCarGroup; - -/** - * 表示汽车的校验器。 - * - * @author 李金绪 - * @since 2024-09-04 - */ -@Validated -public class CarValidate { - /** - * Car 类的校验方法一。 - * - * @param car 表示校验的 Car 对象 {@link Car}。 - */ - public void validate1(@Validated Car car) {} - - /** - * Car 类的校验方法二。 - * - * @param seats 表示输入的座位数量 {@link int}。 - * @param engines 表示输入的发动机数量 {@link int}。 - */ - public void validate2(@Range(min = 0, max = 6, message = "座位数量范围只能在0和6!") int seats, int engines) {} - - /** - * Car 类的校验方法三。 - * - * @param car 表示校验的 Car 对象 {@link Car}。 - */ - public void validate3(@Validated(NormalCarGroup.class) Car car) {} -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Company.java deleted file mode 100644 index 86041ae15..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Company.java +++ /dev/null @@ -1,52 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fitframework.validation.Validated; -import modelengine.fitframework.validation.constraints.Range; - -import java.util.List; - -/** - * 表示测试嵌套校验的数据类。 - * - * @author 李金绪 - * @since 2024-09-06 - */ -public class Company { - @Range(min = 0, max = 1, message = "经理只能有0-1个!") - private int manager; - - @Range(min = 0, max = 100, message = "工人只能有0-100个!") - private int worker; - - @Validated - private Product product; - - @Validated - private List cars; - - /** - * 表示创建一个 {@link Company} 的新实例。 - */ - public Company() {} - - /** - * 表示创建一个 {@link Company} 的新实例。 - * - * @param manager 表示经理数量的 {@code int}。 - * @param worker 表示工人数量的 {@code int}。 - * @param product 表示产品的 {@link Product}。 - * @param cars 表示车辆的 {@link List}{@code <}{@link Car}{@code >}。 - */ - public Company(int manager, int worker, Product product, List cars) { - this.manager = manager; - this.worker = worker; - this.product = product; - this.cars = cars; - } -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/NestedValidate.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/NestedValidate.java deleted file mode 100644 index 4114949a4..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/NestedValidate.java +++ /dev/null @@ -1,84 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fitframework.validation.Validated; - -import java.util.List; -import java.util.Map; - -/** - * 表示公司的校验器。 - * - * @author 李金绪 - * @since 2024-09-06 - */ -public class NestedValidate { - /** - * 嵌套校验的测试方法一。 - * - * @param obj 需要被校验的对象的 {@link Company}。 - */ - public void test1(@Validated Company obj) {} - - /** - * 嵌套校验的测试方法二。 - * - * @param obj 需要被校验的对象的 {@link List}{@code <}{@link Car}{@code >}。 - */ - public void test2(@Validated List obj) {} - - /** - * 嵌套校验的测试方法三。 - * - * @param obj 需要被校验的对象的 {@link List}{@code <}{@link List}{@code <}{@link Car}{@code >>}。 - */ - public void test3(@Validated List> obj) {} - - /** - * 嵌套校验的测试方法四。 - * - * @param obj 需要被校验的对象的 {@link Map}{@code <}{@link String}{@code , }{@link Car}{@code >}。 - */ - public void test4(@Validated Map obj) {} - - /** - * 嵌套校验的测试方法五。 - * - * @param obj 需要被校验的对象的 {@link Map}{@code <}{@link Car}{@code , }{@link Product}{@code >}。 - */ - public void test5(@Validated Map obj) {} - - /** - * 嵌套校验的测试方法六。 - * - * @param obj 需要被校验的对象的 - * {@link Map}{@code <}{@link Car}{@code , }{@link Map}{@code <}{@link Car}{@code , }{@link Product}{@code >>}。 - */ - public void test6(@Validated Map> obj) {} - - /** - * 嵌套校验的测试方法七。 - * - * @param obj 需要被校验的对象的 {@link List}{@code <}{@link Map}{@code <}{@link Car}{@code , }{@link Product}{@code >>}。 - */ - public void test7(@Validated List> obj) {} - - /** - * 嵌套校验的测试方法八。 - * - * @param obj 需要被校验的对象的 {@link Map}{@code <}{@link Car}{@code , }{@link List}{@code <}{@link Product}{@code >>}。 - */ - public void test8(@Validated Map> obj) {} - - /** - * 嵌套校验的测试方法九。 - * - * @param obj 需要被校验的对象的 {@link List}{@code <}{@link Company}{@code >}。 - */ - public void test9(@Validated List obj) {} -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Product.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Product.java deleted file mode 100644 index debb17cd5..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/Product.java +++ /dev/null @@ -1,73 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fitframework.validation.annotation.MaxSize; -import modelengine.fitframework.validation.constraints.NotBlank; -import modelengine.fitframework.validation.constraints.Positive; - -import java.util.List; - -/** - * 表示产品的数据类。 - * - * @author 吕博文 - * @since 2024-08-02 - */ -public class Product { - @NotBlank(message = "产品名不能为空") - private String name; - - @Positive(message = "产品价格必须为正") - private Double price; - - @Positive(message = "产品数量必须为正") - private Integer quantity; - - @NotBlank(message = "产品类别不能为空") - private String category; - - @MaxSize(max = 2) - private List cars; - - /** - * Product 默认构造函数。 - */ - public Product() {} - - /** - * 构造函数。 - * - * @param name 表示名字的 {@link String}。 - * @param price 表示价格的 {@link Double}。 - * @param quantity 表示数量的 {@link Integer}。 - * @param category 表示类别的 {@link String}。 - */ - public Product(String name, Double price, Integer quantity, String category) { - this.name = name; - this.price = price; - this.quantity = quantity; - this.category = category; - } - - /** - * 构造函数。 - * - * @param name 表示名字的 {@link String}。 - * @param price 表示价格的 {@link Double}。 - * @param quantity 表示数量的 {@link Integer}。 - * @param category 表示类别的 {@link String}。 - * @param cars 表示汽车集合的 {@link List}{@code <}{@link Car}{@code >}。 - */ - public Product(String name, Double price, Integer quantity, String category, List cars) { - this.name = name; - this.price = price; - this.quantity = quantity; - this.category = category; - this.cars = cars; - } -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/ProductValidate.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/ProductValidate.java deleted file mode 100644 index ce15a8588..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/ProductValidate.java +++ /dev/null @@ -1,24 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fitframework.validation.Validated; - -/** - * 表示产品的校验器。 - * - * @author 吕博文 - * @since 2024-08-02 - */ -public class ProductValidate { - /** - * Product 类的校验方法一。 - * - * @param product 表示输入的产品 {@link Product}。 - */ - public void validate1(@Validated Product product) {} -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/StudentValidate.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/StudentValidate.java deleted file mode 100644 index 5b886ecb1..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/StudentValidate.java +++ /dev/null @@ -1,29 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fitframework.validation.Validated; -import modelengine.fitframework.validation.constraints.Range; -import modelengine.fitframework.validation.group.StudentGroup; -import modelengine.fitframework.validation.group.TeacherGroup; - -/** - * 学生的校验类。 - * - * @author 邬涨财 - * @since 2023-05-19 - */ -@Validated(StudentGroup.class) -public class StudentValidate { - public void validateStudent( - @Range(min = 7, max = 20, message = "范围要在7~20之内", groups = {StudentGroup.class}) int age) { - } - - public void validateTeacher( - @Range(min = 30, max = 70, message = "范围要在30~70之内", groups = {TeacherGroup.class}) int age) { - } -} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java deleted file mode 100644 index 2c630d81a..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java +++ /dev/null @@ -1,48 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fit.http.annotation.PostMapping; -import modelengine.fit.http.annotation.RequestBody; -import modelengine.fit.http.annotation.RequestMapping; -import modelengine.fitframework.annotation.Component; -import modelengine.fitframework.validation.Validated; -import modelengine.fitframework.validation.group.NormalCarGroup; - -/** - * 表示评估注解验证数据接口集。 - * - * @author 吕博文 - * @since 2024-08-15 - */ -@Component -@RequestMapping(path = "/validation", group = "评估注解验证数据接口") -public class ValidationDataController { - /** - * Car 类默认分组注解验证。 - * - * @param car 表示注解验证类 {@link Car}。 - */ - @PostMapping(path = "/car/default", description = "验证 Car 类默认分组注解") - public void validateCarDefaultGroup(@RequestBody @Validated Car car) {} - - /** - * Car 类特定分组注解验证。 - * - * @param car 表示注解验证类 {@link Car}。 - */ - @PostMapping(path = "/car/carGroup", description = "验证 Car 类特定分组注解") - public void validateCarCarGroup(@RequestBody @Validated(NormalCarGroup.class) Car car) {} - - /** - * Product 类默认分组注解验证。 - * - * @param product 表示注解验证类 {@link Product}。 - */ - @PostMapping(path = "/product/default", description = "验证 Product 类默认分组注解") - public void validateProductDefaultGroup(@RequestBody @Validated Product product) {} -} \ No newline at end of file diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/NormalCarGroup.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/NormalCarGroup.java deleted file mode 100644 index 088243618..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/NormalCarGroup.java +++ /dev/null @@ -1,15 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.group; - -/** - * 正常汽车的分组类。 - * - * @author 李金绪 - * @since 2024-09-04 - */ -public interface NormalCarGroup {} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/OldCarGroup.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/OldCarGroup.java deleted file mode 100644 index 38ca8c43b..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/OldCarGroup.java +++ /dev/null @@ -1,15 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.group; - -/** - * 老旧汽车的分组类。 - * - * @author 李金绪 - * @since 2024-09-04 - */ -public interface OldCarGroup {} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/StudentGroup.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/StudentGroup.java deleted file mode 100644 index 322820820..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/StudentGroup.java +++ /dev/null @@ -1,15 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.group; - -/** - * 学生的分组类。 - * - * @author 邬涨财 - * @since 2023-05-16 - */ -public interface StudentGroup {} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/TeacherGroup.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/TeacherGroup.java deleted file mode 100644 index 4b73386ca..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/group/TeacherGroup.java +++ /dev/null @@ -1,15 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.group; - -/** - * 老师的分组类。 - * - * @author 邬涨财 - * @since 2023-05-19 - */ -public interface TeacherGroup {} diff --git a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/validator/MaxSizeValidator.java b/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/validator/MaxSizeValidator.java deleted file mode 100644 index c06f6cfb8..000000000 --- a/framework/fit/java/fit-extension/fit-validation/src/test/java/modelengine/fitframework/validation/validator/MaxSizeValidator.java +++ /dev/null @@ -1,41 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.validator; - -import static modelengine.fitframework.util.ObjectUtils.cast; - -import modelengine.fitframework.validation.ConstraintValidator; -import modelengine.fitframework.validation.annotation.MaxSize; - -import java.util.List; - -/** - * 表示单集合元素的测试校验类。 - * - * @author 李金绪 - * @since 2025-03-17 - */ -public class MaxSizeValidator implements ConstraintValidator { - private long max; - - @Override - public void initialize(MaxSize constraintAnnotation) { - this.max = constraintAnnotation.max(); - } - - @Override - public boolean isValid(Object value) { - if (value == null) { - return true; - } - if (!(value instanceof List)) { - return false; - } - List valueList = cast(value); - return valueList.size() < this.max; - } -} \ No newline at end of file diff --git a/framework/fit/java/fit-extension/pom.xml b/framework/fit/java/fit-extension/pom.xml index fa747a2fe..ae825bc0d 100644 --- a/framework/fit/java/fit-extension/pom.xml +++ b/framework/fit/java/fit-extension/pom.xml @@ -21,8 +21,6 @@ fit-retry fit-schedule fit-transaction - fit-validation - fit-validation-hibernate From d76a0477345b24f2b7b89e6089e10331b70428c7 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Thu, 7 Aug 2025 18:05:54 +0800 Subject: [PATCH 07/23] =?UTF-8?q?[fit]=20=E4=BF=AE=E6=94=B9=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E6=8F=92=E4=BB=B6=E5=8C=85=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pom.xml | 2 +- .../fitframework/validation/ValidationHandler.java | 0 .../src/main/resources/application.yaml | 0 .../fitframework/validation/ValidationDataControllerTest.java | 0 .../fitframework/validation/ValidationHandlerTest.java | 0 .../modelengine/fitframework/validation/data/Company.java | 0 .../modelengine/fitframework/validation/data/Employee.java | 0 .../fitframework/validation/data/GroupValidateService.java | 0 .../fitframework/validation/data/ValidateService.java | 0 .../validation/data/ValidationDataController.java | 0 .../fitframework/validation/data/ValidationTestData.java | 0 .../pom.xml | 2 +- .../fitframework/validation/ValidationHandler.java | 0 .../src/main/resources/application.yaml | 0 .../fitframework/validation/ValidationDataControllerTest.java | 0 .../fitframework/validation/ValidationHandlerTest.java | 0 .../modelengine/fitframework/validation/data/Company.java | 0 .../modelengine/fitframework/validation/data/Employee.java | 0 .../fitframework/validation/data/GroupValidateService.java | 0 .../fitframework/validation/data/ValidateService.java | 0 .../validation/data/ValidationDataController.java | 0 .../fitframework/validation/data/ValidationTestData.java | 0 framework/fit/java/fit-builtin/plugins/pom.xml | 4 ++-- 23 files changed, 4 insertions(+), 4 deletions(-) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/pom.xml (98%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/src/main/java/modelengine/fitframework/validation/ValidationHandler.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/src/main/resources/application.yaml (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/src/test/java/modelengine/fitframework/validation/data/Company.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/src/test/java/modelengine/fitframework/validation/data/Employee.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/src/test/java/modelengine/fitframework/validation/data/ValidateService.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation-jakarta => fit-validation-hibernate-jakarta}/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/pom.xml (98%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/src/main/java/modelengine/fitframework/validation/ValidationHandler.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/src/main/resources/application.yaml (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/src/test/java/modelengine/fitframework/validation/data/Company.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/src/test/java/modelengine/fitframework/validation/data/Employee.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/src/test/java/modelengine/fitframework/validation/data/ValidateService.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java (100%) rename framework/fit/java/fit-builtin/plugins/{fit-hibernate-validation => fit-validation-hibernate-javax}/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java (100%) diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml similarity index 98% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml index ae2b7b03b..d04352799 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml @@ -9,7 +9,7 @@ 3.6.0-SNAPSHOT - fit-hibernate-validation-jakarta + fit-validation-hibernate-jakarta FIT Hibernate Validation Jakarta FIT Framework Hibernate Validation module provides Validation for args. diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/resources/application.yaml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/resources/application.yaml similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/main/resources/application.yaml rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/resources/application.yaml diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml similarity index 98% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml index d3f7f9387..a23109c12 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml @@ -9,7 +9,7 @@ 3.6.0-SNAPSHOT - fit-hibernate-validation + fit-validation-hibernate-javax FIT Hibernate Validation FIT Framework Hibernate Validation module provides Validation for args. diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/java/modelengine/fitframework/validation/ValidationHandler.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/resources/application.yaml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/resources/application.yaml similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/main/resources/application.yaml rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/resources/application.yaml diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Company.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/Employee.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidateService.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java similarity index 100% rename from framework/fit/java/fit-builtin/plugins/fit-hibernate-validation/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java diff --git a/framework/fit/java/fit-builtin/plugins/pom.xml b/framework/fit/java/fit-builtin/plugins/pom.xml index 6878b97fb..0260ff321 100644 --- a/framework/fit/java/fit-builtin/plugins/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/pom.xml @@ -43,8 +43,8 @@ fit-service-discovery fit-service-registry fit-value-fastjson - fit-hibernate-validation-jakarta - fit-hibernate-validation + fit-validation-hibernate-jakarta + fit-validation-hibernate-javax From ac22cd54d6b6b72cb55cb95c5cb27d4aac962383 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Thu, 7 Aug 2025 18:44:59 +0800 Subject: [PATCH 08/23] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E5=92=8C=E4=BB=A3=E7=A0=81=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/ValidationHandler.java | 16 +- .../fitframework/validation/data/Company.java | 15 -- .../validation/data/Employee.java | 28 +- .../validation/data/ValidateService.java | 224 +++++++++++++++- .../validation/data/ValidationTestData.java | 242 +----------------- .../validation/ValidationHandler.java | 17 +- .../fitframework/validation/data/Company.java | 15 -- .../validation/data/Employee.java | 20 -- .../validation/data/ValidateService.java | 224 +++++++++++++++- .../validation/data/ValidationTestData.java | 216 +--------------- 10 files changed, 477 insertions(+), 540 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index b73cf89da..c5c4186e8 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -33,7 +33,7 @@ /** * 校验入口类。 *

- * 当调用的类或方法参数包含 {@link Validated} 注解时,会对该方法进行校验处理。 + * 当调用的类包含 {@link Validated} 注解时,会对该类公共方法参数进行校验处理。 *

* * @author 阮睿 @@ -54,6 +54,12 @@ public ValidationHandler() { this.validator = validatorFactory.getValidator(); } + /** + * 方法参数校验处理 + * + * @param joinPoint 被拦截的连接点 {@link JoinPoint} + * @param validated 连接点上携带的校验注解 {@link Validated} + */ @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { // 检查方法参数是否包含被 javax.validation.Constraint 标注的校验注解 @@ -78,7 +84,7 @@ public void close() { /** * 检查方法参数是否包含 jakarta.validation 校验注解 * - * @param parameters 方法参数数组 + * @param parameters 方法参数数组 {@link Parameter[]} * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false */ private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { @@ -88,7 +94,7 @@ private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { /** * 检查参数及其泛型类型参数是否包含校验注解 - * @param parameter 方法参数 + * @param parameter 方法参数 {@link Parameter} * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false */ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { @@ -97,7 +103,7 @@ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { /** * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解 - * @param annotatedType 参数注解类型 + * @param annotatedType 参数注解类型 {@link AnnotatedType} * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false */ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { @@ -119,7 +125,7 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { /** * 检查注解是否属于 jakarta.validation 注解 * - * @param annotation 要检查的注解 + * @param annotation 要检查的注解 {@link Annotation} * @return 如果属于 jakarta.validation 注解则返回 true,否则返回 false */ private boolean isJakartaConstraintAnnotation(Annotation annotation) { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java index 4cc02cca1..824a967d8 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -28,19 +28,4 @@ public Company() {} public Company(List employees) { this.employees = employees; } - - public List getEmployees() { - return employees; - } - - public void setEmployees(List employees) { - this.employees = employees; - } - - @Override - public String toString() { - return "Company{" + - "employees=" + employees + - '}'; - } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java index f1808401c..bb0fb1cfe 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -18,38 +18,18 @@ public class Employee { @NotBlank(message = "姓名不能为空") private String name; - + @Min(value = 18, message = "年龄必须大于等于18") private int age; - + public Employee() {} - + public Employee(String name, int age) { this.name = name; this.age = age; } - + 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; - } - - @Override - public String toString() { - return "Employee{" + - "name='" + name + '\'' + - ", age=" + age + - '}'; - } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index 7c7a321f9..185f465aa 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -68,134 +68,346 @@ public void foo2(@Valid Company company) { LOG.debug("{}", company); } - // 新增的校验注解测试方法 + /** + * 测试 NotNull 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testNotNull(@NotNull String value) {} + /** + * 测试 NotEmpty 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testNotEmpty(@NotEmpty String value) {} + /** + * 测试 NotBlank 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testNotBlank(@NotBlank String value) {} + /** + * 测试 Null 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testNull(@Null String value) {} + /** + * 测试 Size 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testSize(@Size(min = 2, max = 10) String value) {} + /** + * 测试 List 的 Size 约束注解。 + * + * @param value 表示输入的 {@code List}。 + */ public void testSizeList(@Size(min = 1, max = 3) List value) {} + /** + * 测试 Min 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testMin(@Min(10) int value) {} + /** + * 测试 Max 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testMax(@Max(100) int value) {} + /** + * 测试 DecimalMin 约束注解。 + * + * @param value 表示输入的 {@code BigDecimal}。 + */ public void testDecimalMin(@DecimalMin("10.5") BigDecimal value) {} + /** + * 测试 DecimalMax 约束注解。 + * + * @param value 表示输入的 {@code BigDecimal}。 + */ public void testDecimalMax(@DecimalMax("100.5") BigDecimal value) {} + /** + * 测试 Positive 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testPositive(@Positive int value) {} + /** + * 测试 PositiveOrZero 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testPositiveOrZero(@PositiveOrZero int value) {} + /** + * 测试 Negative 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testNegative(@Negative int value) {} + /** + * 测试 NegativeOrZero 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testNegativeOrZero(@NegativeOrZero int value) {} + /** + * 测试 Digits 约束注解。 + * + * @param value 表示输入的 {@code BigDecimal}。 + */ public void testDigits(@Digits(integer = 3, fraction = 2) BigDecimal value) {} + /** + * 测试 Past 约束注解。 + * + * @param value 表示输入的 {@code LocalDate}。 + */ public void testPast(@Past LocalDate value) {} + /** + * 测试 PastOrPresent 约束注解。 + * + * @param value 表示输入的 {@code LocalDate}。 + */ public void testPastOrPresent(@PastOrPresent LocalDate value) {} + /** + * 测试 Future 约束注解。 + * + * @param value 表示输入的 {@code LocalDate}。 + */ public void testFuture(@Future LocalDate value) {} + /** + * 测试 FutureOrPresent 约束注解。 + * + * @param value 表示输入的 {@code LocalDate}。 + */ public void testFutureOrPresent(@FutureOrPresent LocalDate value) {} + /** + * 测试 Pattern 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testPattern(@Pattern(regexp = "^[a-zA-Z]+$") String value) {} + /** + * 测试 Email 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testEmail(@Email String value) {} + /** + * 测试 AssertTrue 约束注解。 + * + * @param value 表示输入的 {@code boolean}。 + */ public void testAssertTrue(@AssertTrue boolean value) {} + /** + * 测试 AssertFalse 约束注解。 + * + * @param value 表示输入的 {@code boolean}。 + */ public void testAssertFalse(@AssertFalse boolean value) {} + /** + * 测试 Valid 对象验证。 + * + * @param data 表示输入的 {@code ValidationTestData}。 + */ public void testValidObject(@Valid ValidationTestData data) {} - // Range注解测试方法 + /** + * 测试 Range 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testRange(@Range(min = 10, max = 100, message = "需要在10和100之间") int value) {} + /** + * 测试 BigDecimal 类型的Range约束注解。 + * + * @param value 表示输入的 {@code BigDecimal}。 + */ public void testRangeBigDecimal(@Range(min = 10, max = 100, message = "需要在10和100之间") BigDecimal value) {} - // 默认分组测试方法 + /** + * 验证 Employee 对象。 + * + * @param employee 表示输入的 {@code Employee}。 + */ public void validateEmployee(@Valid Employee employee) { LOG.debug("Validating employee: {}", employee); } + /** + * 验证年龄是否为正数。 + * + * @param age 表示输入的 {@code int}。 + */ public void validateAge(@Positive(message = "必须是正数") int age) { LOG.debug("Validating age: {}", age); } + /** + * 验证姓名和年龄。 + * + * @param name 表示输入的 {@code String}。 + * @param age 表示输入的 {@code int}。 + */ public void validateNameAndAge(@NotBlank String name, @Positive int age) { LOG.debug("Validating name: {} and age: {}", name, age); } - // 分组验证代理方法 + /** + * 验证高级分组数据。 + * + * @param data 表示输入的 {@code ValidationTestData}。 + */ public void validateAdvancedGroup(ValidationTestData data) { if (advancedValidateService != null) { advancedValidateService.validateAdvancedGroup(data); } } + /** + * 验证学生年龄。 + * + * @param age 表示输入的 {@code int}。 + */ public void validateStudentAge(int age) { if (studentValidateService != null) { studentValidateService.validateStudentAge(age); } } + /** + * 验证教师年龄。 + * + * @param age 表示输入的 {@code int}。 + */ public void validateTeacherAge(int age) { if (teacherValidateService != null) { teacherValidateService.validateTeacherAge(age); } } - // 嵌套测试方法 + /** + * 验证公司对象。 + * + * @param company 表示输入的 {@code Company}。 + */ public void validateCompany(@Valid Company company) { LOG.debug("Validating company: {}", company); } + /** + * 验证员工列表。 + * + * @param employees 表示输入的 {@code List}。 + */ public void validateEmployeeList(List<@Valid Employee> employees) { LOG.debug("Validating employee list: {}", employees); } + /** + * 验证嵌套员工列表。 + * + * @param nestedList 表示输入的 {@code List>}。 + */ public void validateNestedEmployeeList(List> nestedList) { LOG.debug("Validating nested employee list: {}", nestedList); } + /** + * 验证员工映射。 + * + * @param employeeMap 表示输入的 {@code Map}。 + */ public void validateEmployeeMap(@Valid Map employeeMap) { LOG.debug("Validating employee map: {}", employeeMap); } + /** + * 验证员工数据映射。 + * + * @param map 表示输入的 {@code Map}。 + */ public void validateEmployeeDataMap(@Valid Map map) { LOG.debug("Validating employee data map: {}", map); } + /** + * 验证嵌套员工数据映射。 + * + * @param nestedMap 表示输入的 {@code Map>}。 + */ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map> nestedMap) { LOG.debug("Validating nested employee data map: {}", nestedMap); } + /** + * 验证员工映射列表。 + * + * @param listOfMaps 表示输入的 {@code List>}。 + */ public void validateEmployeeMapList(List> listOfMaps) { LOG.debug("Validating employee map list: {}", listOfMaps); } + /** + * 验证员工数据列表映射。 + * + * @param map 表示输入的 {@code Map>}。 + */ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { LOG.debug("Validating employee data list map: {}", map); } + /** + * 验证公司列表。 + * + * @param companies 表示输入的 {@code List}。 + */ public void validateCompanyList(@Valid List companies) { LOG.debug("Validating company list: {}", companies); } - // 混合场景测试方法 + /** + * 验证混合类型数据。 + * + * @param value 表示输入的 {@code int}。 + * @param employee 表示输入的 {@code Employee}。 + */ public void validateMixed(@Positive int value, @Valid Employee employee) { LOG.debug("Validating mixed primitive {} and object {}", value, employee); } + /** + * 验证混合集合数据。 + * + * @param list1 表示输入的 {@code List}。 + * @param list2 表示输入的 {@code List}。 + */ public void validateMixedCollections(@NotNull List list1, @NotEmpty List list2) { LOG.debug("Validating mixed collections: {} and {}", list1, list2); } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index 63d56492d..5f345b01b 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -17,282 +17,68 @@ * @since 2025-07-18 */ public class ValidationTestData { - + // 分组接口定义 - public interface BasicGroup {} public interface AdvancedGroup {} public interface StudentGroup {} public interface TeacherGroup {} - + @NotBlank(message = "名称不能为空") private String name; - + @Min(value = 0, message = "年龄必须大于等于0") @Max(value = 150, message = "年龄必须小于等于150") @Max(value = 200, message = "高级组年龄必须小于等于200", groups = AdvancedGroup.class) private Integer age; - + @NotBlank(message = "描述不能为空") private String description; - + @NotBlank(message = "内容不能为空白") private String content; - - @Size(min = 2, max = 10, message = "标题长度必须在2-10之间") - private String title; - - @DecimalMin(value = "0.0", message = "价格必须大于等于0") - @DecimalMax(value = "999.99", message = "价格必须小于等于999.99") - private BigDecimal price; - + @Positive(message = "数量必须是正数") private Integer quantity; - - @PositiveOrZero(message = "库存必须是正数或零") - private int stock; - + @Negative(message = "折扣必须是负数") private BigDecimal discount; - - @NegativeOrZero(message = "债务必须是负数或零") - private int debt; - - @Digits(integer = 3, fraction = 2, message = "金额格式不正确") - private BigDecimal amount; - - @Past(message = "出生日期必须是过去时间") - private LocalDate birthDate; - - @PastOrPresent(message = "创建时间必须是过去或现在时间") - private LocalDate createDate; - - @Future(message = "到期时间必须是未来时间") - private LocalDate expireDate; - - @FutureOrPresent(message = "更新时间必须是未来或现在时间") - private LocalDate updateDate; - - @Pattern(regexp = "^[a-zA-Z]+$", message = "代码只能包含字母") - private String code; - - @Email(message = "邮箱格式不正确") - private String email; - + @AssertTrue(message = "必须同意条款") private Boolean agreed; - - @AssertFalse(message = "必须取消订阅") - private boolean subscribed; - + // 构造函数 public ValidationTestData() {} - - public ValidationTestData(String name, Integer age) { - this.name = name; - this.age = age; - } - - public ValidationTestData(String name, String description, String content, String title, - int age, BigDecimal price, int quantity, int stock, BigDecimal discount, - int debt, BigDecimal amount, LocalDate birthDate, LocalDate createDate, - LocalDate expireDate, LocalDate updateDate, String code, String email, - Boolean agreed, boolean subscribed) { - this.name = name; - this.description = description; - this.content = content; - this.title = title; - this.age = age; - this.price = price; - this.quantity = quantity; - this.stock = stock; - this.discount = discount; - this.debt = debt; - this.amount = amount; - this.birthDate = birthDate; - this.createDate = createDate; - this.expireDate = expireDate; - this.updateDate = updateDate; - this.code = code; - this.email = email; - this.agreed = agreed; - this.subscribed = subscribed; - } - + // Getters and Setters public String getName() { return name; } - + public void setName(String name) { this.name = name; } - - public Integer getAge() { - return age; - } - + public void setAge(Integer age) { this.age = age; } - - public String getDescription() { - return description; - } - + public void setDescription(String description) { this.description = description; } - - public String getContent() { - return content; - } - + public void setContent(String content) { this.content = content; } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public BigDecimal getPrice() { - return price; - } - - public void setPrice(BigDecimal price) { - this.price = price; - } - - public Integer getQuantity() { - return quantity; - } public void setQuantity(Integer quantity) { this.quantity = quantity; } - public int getStock() { - return stock; - } - - public void setStock(int stock) { - this.stock = stock; - } - - public BigDecimal getDiscount() { - return discount; - } - public void setDiscount(BigDecimal discount) { this.discount = discount; } - public int getDebt() { - return debt; - } - - public void setDebt(int debt) { - this.debt = debt; - } - - public BigDecimal getAmount() { - return amount; - } - - public void setAmount(BigDecimal amount) { - this.amount = amount; - } - - public LocalDate getBirthDate() { - return birthDate; - } - - public void setBirthDate(LocalDate birthDate) { - this.birthDate = birthDate; - } - - public LocalDate getCreateDate() { - return createDate; - } - - public void setCreateDate(LocalDate createDate) { - this.createDate = createDate; - } - - public LocalDate getExpireDate() { - return expireDate; - } - - public void setExpireDate(LocalDate expireDate) { - this.expireDate = expireDate; - } - - public LocalDate getUpdateDate() { - return updateDate; - } - - public void setUpdateDate(LocalDate updateDate) { - this.updateDate = updateDate; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public Boolean getAgreed() { - return agreed; - } - public void setAgreed(Boolean agreed) { this.agreed = agreed; } - - public boolean isSubscribed() { - return subscribed; - } - - public void setSubscribed(boolean subscribed) { - this.subscribed = subscribed; - } - - @Override - public String toString() { - return "ValidationTestData{" + - "name='" + name + '\'' + - ", age=" + age + - ", description='" + description + '\'' + - ", content='" + content + '\'' + - ", title='" + title + '\'' + - ", price=" + price + - ", quantity=" + quantity + - ", stock=" + stock + - ", discount=" + discount + - ", debt=" + debt + - ", amount=" + amount + - ", birthDate=" + birthDate + - ", createDate=" + createDate + - ", expireDate=" + expireDate + - ", updateDate=" + updateDate + - ", code='" + code + '\'' + - ", email='" + email + '\'' + - ", agreed=" + agreed + - ", subscribed=" + subscribed + - '}'; - } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 3c60ac98d..0c951e8a3 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -20,7 +20,6 @@ import java.lang.reflect.AnnotatedParameterizedType; import java.lang.reflect.AnnotatedType; import java.lang.reflect.Parameter; -import java.util.ArrayList; import java.util.Arrays; import java.util.Set; @@ -34,7 +33,7 @@ /** * 校验入口类。 *

- * 当调用的类或方法参数包含 {@link Validated} 注解时,会对该方法进行校验处理。 + * 当调用的类包含 {@link Validated} 注解时,会对该类公共方法参数进行校验处理。 *

* * @author 阮睿 @@ -55,6 +54,12 @@ public class ValidationHandler implements AutoCloseable { this.validator = validatorFactory.getValidator(); } + /** + * 方法参数校验处理 + * + * @param joinPoint 被拦截的连接点 {@link JoinPoint} + * @param validated 连接点上携带的校验注解 {@link Validated} + */ @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { // 检查方法参数是否包含被 jakarta.validation.Constraint 标注的校验注解 @@ -79,7 +84,7 @@ public void close() { /** * 检查方法参数是否包含 javax.validation 校验注解 * - * @param parameters 方法参数数组 + * @param parameters 方法参数数组 {@link Parameter[]} * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false */ private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { @@ -89,7 +94,7 @@ private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { /** * 检查参数及其泛型类型参数是否包含校验注解 - * @param parameter 方法参数数组 + * @param parameter 方法参数数组 {@link Parameter} * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false */ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { @@ -98,7 +103,7 @@ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { /** * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解 - * @param annotatedType 参数注解类型 + * @param annotatedType 参数注解类型 {@link AnnotatedType} * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false */ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { @@ -120,7 +125,7 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { /** * 检查注解是否属于 javax.validation 注解 * - * @param annotation 要检查的注解 + * @param annotation 要检查的注解 {@link Annotation} * @return 如果属于 javax.validation 注解则返回 true,否则返回 false */ private boolean isJavaxConstraintAnnotation(Annotation annotation) { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java index b503e037f..09d467b9c 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -28,19 +28,4 @@ public Company() {} public Company(List employees) { this.employees = employees; } - - public List getEmployees() { - return employees; - } - - public void setEmployees(List employees) { - this.employees = employees; - } - - @Override - public String toString() { - return "Company{" + - "employees=" + employees + - '}'; - } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java index 976ef05e0..a22ffb88b 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -32,24 +32,4 @@ public Employee(String name, int age) { 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; - } - - @Override - public String toString() { - return "Employee{" + - "name='" + name + '\'' + - ", age=" + age + - '}'; - } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index f9ef6155a..c62cc716d 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -68,134 +68,346 @@ public void foo2(@Valid Company company) { LOG.debug("{}", company); } - // 新增的校验注解测试方法 + /** + * 测试 NotNull 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testNotNull(@NotNull String value) {} + /** + * 测试 NotEmpty 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testNotEmpty(@NotEmpty String value) {} + /** + * 测试 NotBlank 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testNotBlank(@NotBlank String value) {} + /** + * 测试 Null 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testNull(@Null String value) {} + /** + * 测试 Size 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testSize(@Size(min = 2, max = 10) String value) {} + /** + * 测试 List 的 Size 约束注解。 + * + * @param value 表示输入的 {@code List}。 + */ public void testSizeList(@Size(min = 1, max = 3) List value) {} + /** + * 测试 Min 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testMin(@Min(10) int value) {} + /** + * 测试 Max 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testMax(@Max(100) int value) {} + /** + * 测试 DecimalMin 约束注解。 + * + * @param value 表示输入的 {@code BigDecimal}。 + */ public void testDecimalMin(@DecimalMin("10.5") BigDecimal value) {} + /** + * 测试 DecimalMax 约束注解。 + * + * @param value 表示输入的 {@code BigDecimal}。 + */ public void testDecimalMax(@DecimalMax("100.5") BigDecimal value) {} + /** + * 测试 Positive 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testPositive(@Positive int value) {} + /** + * 测试 PositiveOrZero 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testPositiveOrZero(@PositiveOrZero int value) {} + /** + * 测试 Negative 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testNegative(@Negative int value) {} + /** + * 测试 NegativeOrZero 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testNegativeOrZero(@NegativeOrZero int value) {} + /** + * 测试 Digits 约束注解。 + * + * @param value 表示输入的 {@code BigDecimal}。 + */ public void testDigits(@Digits(integer = 3, fraction = 2) BigDecimal value) {} + /** + * 测试 Past 约束注解。 + * + * @param value 表示输入的 {@code LocalDate}。 + */ public void testPast(@Past LocalDate value) {} + /** + * 测试 PastOrPresent 约束注解。 + * + * @param value 表示输入的 {@code LocalDate}。 + */ public void testPastOrPresent(@PastOrPresent LocalDate value) {} + /** + * 测试 Future 约束注解。 + * + * @param value 表示输入的 {@code LocalDate}。 + */ public void testFuture(@Future LocalDate value) {} + /** + * 测试 FutureOrPresent 约束注解。 + * + * @param value 表示输入的 {@code LocalDate}。 + */ public void testFutureOrPresent(@FutureOrPresent LocalDate value) {} + /** + * 测试 Pattern 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testPattern(@Pattern(regexp = "^[a-zA-Z]+$") String value) {} + /** + * 测试 Email 约束注解。 + * + * @param value 表示输入的 {@code String}。 + */ public void testEmail(@Email String value) {} + /** + * 测试 AssertTrue 约束注解。 + * + * @param value 表示输入的 {@code boolean}。 + */ public void testAssertTrue(@AssertTrue boolean value) {} + /** + * 测试 AssertFalse 约束注解。 + * + * @param value 表示输入的 {@code boolean}。 + */ public void testAssertFalse(@AssertFalse boolean value) {} + /** + * 测试 Valid 对象验证。 + * + * @param data 表示输入的 {@code ValidationTestData}。 + */ public void testValidObject(@Valid ValidationTestData data) {} - // Range注解测试方法 + /** + * 测试 Range 约束注解。 + * + * @param value 表示输入的 {@code int}。 + */ public void testRange(@Range(min = 10, max = 100, message = "需要在10和100之间") int value) {} + /** + * 测试 BigDecimal 类型的Range约束注解。 + * + * @param value 表示输入的 {@code BigDecimal}。 + */ public void testRangeBigDecimal(@Range(min = 10, max = 100, message = "需要在10和100之间") BigDecimal value) {} - // 默认分组测试方法 + /** + * 验证 Employee 对象。 + * + * @param employee 表示输入的 {@code Employee}。 + */ public void validateEmployee(@Valid Employee employee) { LOG.debug("Validating employee: {}", employee); } + /** + * 验证年龄是否为正数。 + * + * @param age 表示输入的 {@code int}。 + */ public void validateAge(@Positive(message = "必须是正数") int age) { LOG.debug("Validating age: {}", age); } + /** + * 验证姓名和年龄。 + * + * @param name 表示输入的 {@code String}。 + * @param age 表示输入的 {@code int}。 + */ public void validateNameAndAge(@NotBlank String name, @Positive int age) { LOG.debug("Validating name: {} and age: {}", name, age); } - // 分组验证代理方法 + /** + * 验证高级分组数据。 + * + * @param data 表示输入的 {@code ValidationTestData}。 + */ public void validateAdvancedGroup(ValidationTestData data) { if (advancedValidateService != null) { advancedValidateService.validateAdvancedGroup(data); } } + /** + * 验证学生年龄。 + * + * @param age 表示输入的 {@code int}。 + */ public void validateStudentAge(int age) { if (studentValidateService != null) { studentValidateService.validateStudentAge(age); } } + /** + * 验证教师年龄。 + * + * @param age 表示输入的 {@code int}。 + */ public void validateTeacherAge(int age) { if (teacherValidateService != null) { teacherValidateService.validateTeacherAge(age); } } - // 嵌套测试方法 + /** + * 验证公司对象。 + * + * @param company 表示输入的 {@code Company}。 + */ public void validateCompany(@Valid Company company) { LOG.debug("Validating company: {}", company); } + /** + * 验证员工列表。 + * + * @param employees 表示输入的 {@code List}。 + */ public void validateEmployeeList(List<@Valid Employee> employees) { LOG.debug("Validating employee list: {}", employees); } + /** + * 验证嵌套员工列表。 + * + * @param nestedList 表示输入的 {@code List>}。 + */ public void validateNestedEmployeeList(List> nestedList) { LOG.debug("Validating nested employee list: {}", nestedList); } + /** + * 验证员工映射。 + * + * @param employeeMap 表示输入的 {@code Map}。 + */ public void validateEmployeeMap(@Valid Map employeeMap) { LOG.debug("Validating employee map: {}", employeeMap); } + /** + * 验证员工数据映射。 + * + * @param map 表示输入的 {@code Map}。 + */ public void validateEmployeeDataMap(@Valid Map map) { LOG.debug("Validating employee data map: {}", map); } + /** + * 验证嵌套员工数据映射。 + * + * @param nestedMap 表示输入的 {@code Map>}。 + */ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map> nestedMap) { LOG.debug("Validating nested employee data map: {}", nestedMap); } + /** + * 验证员工映射列表。 + * + * @param listOfMaps 表示输入的 {@code List>}。 + */ public void validateEmployeeMapList(List> listOfMaps) { LOG.debug("Validating employee map list: {}", listOfMaps); } + /** + * 验证员工数据列表映射。 + * + * @param map 表示输入的 {@code Map>}。 + */ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { LOG.debug("Validating employee data list map: {}", map); } + /** + * 验证公司列表。 + * + * @param companies 表示输入的 {@code List}。 + */ public void validateCompanyList(@Valid List companies) { LOG.debug("Validating company list: {}", companies); } - // 混合场景测试方法 + /** + * 验证混合类型数据。 + * + * @param value 表示输入的 {@code int}。 + * @param employee 表示输入的 {@code Employee}。 + */ public void validateMixed(@Positive int value, @Valid Employee employee) { LOG.debug("Validating mixed primitive {} and object {}", value, employee); } + /** + * 验证混合集合数据。 + * + * @param list1 表示输入的 {@code List}。 + * @param list2 表示输入的 {@code List}。 + */ public void validateMixedCollections(@NotNull List list1, @NotEmpty List list2) { LOG.debug("Validating mixed collections: {} and {}", list1, list2); } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index 56ab50d19..c6d37c10e 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -17,9 +17,8 @@ * @since 2025-07-18 */ public class ValidationTestData { - + // 分组接口定义 - public interface BasicGroup {} public interface AdvancedGroup {} public interface StudentGroup {} public interface TeacherGroup {} @@ -38,86 +37,18 @@ public interface TeacherGroup {} @NotBlank(message = "内容不能为空白") private String content; - @Size(min = 2, max = 10, message = "标题长度必须在2-10之间") - private String title; - - @DecimalMin(value = "0.0", message = "价格必须大于等于0") - @DecimalMax(value = "999.99", message = "价格必须小于等于999.99") - private BigDecimal price; - @Positive(message = "数量必须是正数") private Integer quantity; - @PositiveOrZero(message = "库存必须是正数或零") - private int stock; - @Negative(message = "折扣必须是负数") private BigDecimal discount; - @NegativeOrZero(message = "债务必须是负数或零") - private int debt; - - @Digits(integer = 3, fraction = 2, message = "金额格式不正确") - private BigDecimal amount; - - @Past(message = "出生日期必须是过去时间") - private LocalDate birthDate; - - @PastOrPresent(message = "创建时间必须是过去或现在时间") - private LocalDate createDate; - - @Future(message = "到期时间必须是未来时间") - private LocalDate expireDate; - - @FutureOrPresent(message = "更新时间必须是未来或现在时间") - private LocalDate updateDate; - - @Pattern(regexp = "^[a-zA-Z]+$", message = "代码只能包含字母") - private String code; - - @Email(message = "邮箱格式不正确") - private String email; - @AssertTrue(message = "必须同意条款") private Boolean agreed; - @AssertFalse(message = "必须取消订阅") - private boolean subscribed; - // 构造函数 public ValidationTestData() {} - public ValidationTestData(String name, Integer age) { - this.name = name; - this.age = age; - } - - public ValidationTestData(String name, String description, String content, String title, - int age, BigDecimal price, int quantity, int stock, BigDecimal discount, - int debt, BigDecimal amount, LocalDate birthDate, LocalDate createDate, - LocalDate expireDate, LocalDate updateDate, String code, String email, - Boolean agreed, boolean subscribed) { - this.name = name; - this.description = description; - this.content = content; - this.title = title; - this.age = age; - this.price = price; - this.quantity = quantity; - this.stock = stock; - this.discount = discount; - this.debt = debt; - this.amount = amount; - this.birthDate = birthDate; - this.createDate = createDate; - this.expireDate = expireDate; - this.updateDate = updateDate; - this.code = code; - this.email = email; - this.agreed = agreed; - this.subscribed = subscribed; - } - // Getters and Setters public String getName() { return name; @@ -127,172 +58,27 @@ public void setName(String name) { this.name = name; } - public Integer getAge() { - return age; - } - public void setAge(Integer age) { this.age = age; } - public String getDescription() { - return description; - } - public void setDescription(String description) { this.description = description; } - public String getContent() { - return content; - } - public void setContent(String content) { this.content = content; } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public BigDecimal getPrice() { - return price; - } - - public void setPrice(BigDecimal price) { - this.price = price; - } - - public Integer getQuantity() { - return quantity; - } public void setQuantity(Integer quantity) { this.quantity = quantity; } - public int getStock() { - return stock; - } - - public void setStock(int stock) { - this.stock = stock; - } - - public BigDecimal getDiscount() { - return discount; - } - public void setDiscount(BigDecimal discount) { this.discount = discount; } - public int getDebt() { - return debt; - } - - public void setDebt(int debt) { - this.debt = debt; - } - - public BigDecimal getAmount() { - return amount; - } - - public void setAmount(BigDecimal amount) { - this.amount = amount; - } - - public LocalDate getBirthDate() { - return birthDate; - } - - public void setBirthDate(LocalDate birthDate) { - this.birthDate = birthDate; - } - - public LocalDate getCreateDate() { - return createDate; - } - - public void setCreateDate(LocalDate createDate) { - this.createDate = createDate; - } - - public LocalDate getExpireDate() { - return expireDate; - } - - public void setExpireDate(LocalDate expireDate) { - this.expireDate = expireDate; - } - - public LocalDate getUpdateDate() { - return updateDate; - } - - public void setUpdateDate(LocalDate updateDate) { - this.updateDate = updateDate; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public Boolean getAgreed() { - return agreed; - } - public void setAgreed(Boolean agreed) { this.agreed = agreed; } - - public boolean isSubscribed() { - return subscribed; - } - - public void setSubscribed(boolean subscribed) { - this.subscribed = subscribed; - } - - @Override - public String toString() { - return "ValidationTestData{" + - "name='" + name + '\'' + - ", age=" + age + - ", description='" + description + '\'' + - ", content='" + content + '\'' + - ", title='" + title + '\'' + - ", price=" + price + - ", quantity=" + quantity + - ", stock=" + stock + - ", discount=" + discount + - ", debt=" + debt + - ", amount=" + amount + - ", birthDate=" + birthDate + - ", createDate=" + createDate + - ", expireDate=" + expireDate + - ", updateDate=" + updateDate + - ", code='" + code + '\'' + - ", email='" + email + '\'' + - ", agreed=" + agreed + - ", subscribed=" + subscribed + - '}'; - } } From 2f5c28ebaaee82f2565c015c9a13e3ee19d9204a Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Tue, 12 Aug 2025 09:04:29 +0800 Subject: [PATCH 09/23] =?UTF-8?q?[fit]=20=E5=A4=84=E7=90=86=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...37\350\203\275\347\273\204\344\273\266.md" | 178 +++++++------- .../validation/ValidationHandler.java | 75 +++--- .../ValidationDataControllerTest.java | 25 +- .../validation/ValidationHandlerTest.java | 229 ++++++++---------- .../fitframework/validation/data/Company.java | 7 +- .../validation/data/GroupValidateService.java | 19 +- .../validation/data/ValidateService.java | 62 +++-- .../data/ValidationDataController.java | 3 +- .../validation/data/ValidationTestData.java | 11 +- .../validation/ValidationHandler.java | 64 ++--- .../ValidationDataControllerTest.java | 25 +- .../validation/ValidationHandlerTest.java | 226 +++++++---------- .../fitframework/validation/data/Company.java | 7 +- .../validation/data/Employee.java | 8 +- .../validation/data/GroupValidateService.java | 12 +- .../validation/data/ValidateService.java | 63 +++-- .../validation/data/ValidationTestData.java | 37 +-- 17 files changed, 526 insertions(+), 525 deletions(-) diff --git "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" index 919102f40..ae013f758 100644 --- "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" +++ "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" @@ -210,21 +210,19 @@ public class MyEventHandler implements EventHandler { } ``` - # 12.3 Validation 插件 +FIT 框架提供了基于 Hibernate Validator 的数据校验功能,支持对方法参数进行自动校验。 -FIT框架提供了基于Hibernate Validator的数据校验功能,支持对方法参数进行自动校验。框架提供了两个版本的校验插件以适配不同的Java环境,与12.3的扩展校验实现不同在于,12.3只处理FIT框架提供的校验注解,而12.3则支持所有符合javax.validation规范或者jakarta.validation规范的校验注解: - -- `fit-hibernate-validation`:基于javax.validation规范,适用于传统Java EE环境 -- `fit-hibernate-validation-jakarta`:基于jakarta.validation规范,适用于Jakarta EE环境 +- `fit-hibernate-validation`:基于 javax.validation 规范,适用于传统 Java EE 环境 +- `fit-hibernate-validation-jakarta`:基于 jakarta.validation 规范,适用于 Jakarta EE 环境 约束由约束注解和约束验证实现的组合定义。约束注解可以应用于类、方法、字段或其他约束注解(在组合的情况下)。 ## 12.3.1 依赖 +根据您的 Java 环境选择对应的插件: -根据您的Java环境选择对应的插件: +**传统 Java EE 环境(javax):** -**传统Java EE环境(javax):** ```xml org.fitframework.plugin @@ -233,7 +231,8 @@ FIT框架提供了基于Hibernate Validator的数据校验功能,支持对方 ``` -**Jakarta EE环境:** +**Jakarta EE 环境:** + ```xml org.fitframework.plugin @@ -242,9 +241,10 @@ FIT框架提供了基于Hibernate Validator的数据校验功能,支持对方 ``` -同时根据您的Java环境选择对应的标准依赖: +同时根据您的 Java 环境选择对应的标准依赖: + +**传统 Java EE 环境(javax):** -**传统Java EE环境(javax):** ```xml javax.validation @@ -253,7 +253,8 @@ FIT框架提供了基于Hibernate Validator的数据校验功能,支持对方 ``` -**Jakarta EE环境:** +**Jakarta EE 环境:** + ```xml jakarta.validation @@ -266,37 +267,37 @@ FIT框架提供了基于Hibernate Validator的数据校验功能,支持对方 ### 基本用法 -1. **类级别校验**:在类上添加`@Validated`注解,框架会自动对该类的所有方法参数进行校验。 +1. **类级别校验**:在类上添加 `@Validated` 注解,框架会自动对该类的所有方法参数进行校验。 ```java @Component @Validated public class UserController { - + public void createUser(@NotBlank(message = "用户名不能为空") String username, - @Min(value = 18, message = "年龄必须大于等于18") Integer age) { + @Min(value = 18, message = "年龄必须大于等于18") Integer age) { // 业务逻辑 } } ``` -2. **复杂对象校验**:对于复杂对象,需要在参数前添加`@Valid`注解,并在对象内部字段上添加校验注解。 +2. **复杂对象校验**:对于复杂对象,需要在参数前添加 `@Valid` 注解,并在对象内部字段上添加校验注解。 ```java public class UserDto { @NotBlank(message = "名称不能为空") private String name; - + @Min(value = 0, message = "年龄必须大于等于0") @Max(value = 150, message = "年龄必须小于等于150") private Integer age; - + @Email(message = "邮箱格式不正确") private String email; - + @Pattern(regexp = "^[a-zA-Z]+$", message = "代码只能包含字母") private String code; - + // getter/setter... } ``` @@ -310,112 +311,120 @@ public void createUser(@RequestBody @Valid UserDto userDto) { ### 泛型类型校验 -3. **泛型类型参数校验**:方法的某个入参是泛型类型,如`Collection`、`Map`的参数类型,需要在校验对象前添加`@Valid`注解(按照hibernate validator reference推荐,但您仍然可以以@Valid List 这样的方式添加注解,但不能以@Valid List> 的方式添加注解),否则添加的约束规则不生效,并在泛型内部类型对需要校验的字段添加所需的校验注解。 +3. **泛型类型参数校验**:方法的某个入参是泛型类型,如 `Collection`、`Map` 的参数类型,需要在校验对象前添加 `@Valid` + 注解(按照 Hibernate Validator reference 推荐,但您仍然可以以 @Valid List 这样的方式添加注解,但不能以 @Valid List> 的方式添加注解),否则添加的约束规则不生效,并在泛型内部类型对需要校验的字段添加所需的校验注解。 ```java -// List类型参数校验 +// List 类型参数校验 public void createUsers(List<@Valid UserDto> users) { - // 会对List中每个UserDto对象进行校验 + // 会对 List 中每个 UserDto 对象进行校验 } -// Map类型参数校验 +// Map 类型参数校验 public void processUserData(Map userMap) { - // 会对Map中每个UserDto值进行校验 + // 会对 Map 中每个 UserDto 值进行校验 } -// Set类型参数校验 -public void updateUsers(Set @Valid users) { - // 会对Set中每个UserDto对象进行校验 +// Set 类型参数校验 +public void updateUsers(Set<@Valid UserDto> users) { + // 会对 Set 中每个 UserDto 对象进行校验 } ``` ### 嵌套对象校验 -4. **嵌套校验支持**:FIT支持对嵌套校验,即当泛型类型中内嵌泛型类型、非基本数据类型的字段中包含非基本数据类型时,需要在嵌套字段上添加`@Valid`注解。 +4. **嵌套校验支持**:FIT 支持对嵌套校验,即当泛型类型中内嵌泛型类型、非基本数据类型的字段中包含非基本数据类型时,需要在嵌套字段上添加 `@Valid` + 注解。 ```java public class CompanyDto { @NotBlank(message = "公司名称不能为空") private String name; - + @Min(value = 0, message = "员工数量不能为负数") private Integer employeeCount; - + // 嵌套单个对象校验 @Valid @NotNull(message = "经理信息不能为空") private UserDto manager; - + // 嵌套集合对象校验 @Valid @Size(min = 1, message = "至少需要一个员工") private List employees; - - // 嵌套Map对象校验 + + // 嵌套 Map 对象校验 @Valid private Map departments; - + // getter/setter... } public class DepartmentDto { @NotBlank(message = "部门名称不能为空") private String departmentName; - + @Valid private List members; - + // getter/setter... } // 使用示例 public void createCompany(@Valid CompanyDto company) { - // 会递归校验company及其所有嵌套对象 + // 会递归校验 company 及其所有嵌套对象 } // 复杂嵌套泛型校验 public void processComplexData(Map> companyGroups) { - // 会校验Map中每个List,以及List中每个CompanyDto及其嵌套对象 + // 会校验 Map 中每个 List,以及 List 中每个 CompanyDto 及其嵌套对象 } ``` -5. **校验失败处理**:方法被调用时,如果传入的实际参数与约束规则不符,会直接抛出`ConstraintViolationException`,表明参数校验失败。 +5. **校验失败处理**:方法被调用时,如果传入的实际参数与约束规则不符,会直接抛出 `ConstraintViolationException`,表明参数校验失败。 ### 支持的校验注解 -框架支持完整的Bean Validation注解集合: +框架支持完整的 Bean Validation 注解集合: #### 空值校验 -- `@NotNull`:值不能为null -- `@NotEmpty`:值不能为null且不能为空(适用于字符串、集合、数组、Map) -- `@NotBlank`:字符串不能为null、空字符串或只包含空白字符 -- `@Null`:值必须为null + +- `@NotNull`:值不能为 null +- `@NotEmpty`:值不能为 null 且不能为空(适用于字符串、集合、数组、Map) +- `@NotBlank`:字符串不能为 null、空字符串或只包含空白字符 +- `@Null`:值必须为 null #### 布尔值校验 -- `@AssertTrue`:值必须为true -- `@AssertFalse`:值必须为false + +- `@AssertTrue`:值必须为 true +- `@AssertFalse`:值必须为 false #### 数值校验 + - `@Min(value)`:数值必须大于等于指定值 - `@Max(value)`:数值必须小于等于指定值 - `@DecimalMin(value)`:小数值必须大于等于指定值 - `@DecimalMax(value)`:小数值必须小于等于指定值 -- `@Positive`:数值必须为正数(大于0) -- `@PositiveOrZero`:数值必须为正数或零(大于等于0) -- `@Negative`:数值必须为负数(小于0) -- `@NegativeOrZero`:数值必须为负数或零(小于等于0) -- `@Digits(integer, fraction)`:数字格式校验,integer指定整数位数,fraction指定小数位数 +- `@Positive`:数值必须为正数(大于 0) +- `@PositiveOrZero`:数值必须为正数或零(大于等于 0) +- `@Negative`:数值必须为负数(小于 0) +- `@NegativeOrZero`:数值必须为负数或零(小于等于 0) +- `@Digits(integer, fraction)`:数字格式校验,integer 指定整数位数,fraction 指定小数位数 #### 大小校验 -- `@Size(min, max)`:字符串、集合、数组、Map的大小必须在指定范围内 + +- `@Size(min, max)`:字符串、集合、数组、Map 的大小必须在指定范围内 #### 时间校验 + - `@Past`:日期必须是过去的时间 - `@PastOrPresent`:日期必须是过去或现在的时间 - `@Future`:日期必须是未来的时间 - `@FutureOrPresent`:日期必须是未来或现在的时间 #### 格式校验 + - `@Pattern(regexp)`:字符串必须匹配指定的正则表达式 - `@Email`:字符串必须是有效的邮箱格式 @@ -423,39 +432,39 @@ public void processComplexData(Map> companyGroup ```java public class CompleteValidationDto { - @NotNull(message = "ID不能为空") + @NotNull(message = "ID 不能为空") private Long id; - + @NotBlank(message = "用户名不能为空") - @Size(min = 2, max = 20, message = "用户名长度必须在2-20之间") + @Size(min = 2, max = 20, message = "用户名长度必须在 2-20 之间") @Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母、数字和下划线") private String username; - + @Email(message = "邮箱格式不正确") private String email; - - @Min(value = 18, message = "年龄必须大于等于18") - @Max(value = 100, message = "年龄必须小于等于100") + + @Min(value = 18, message = "年龄必须大于等于 18") + @Max(value = 100, message = "年龄必须小于等于 100") private Integer age; - + @DecimalMin(value = "0.0", message = "薪资不能为负数") - @DecimalMax(value = "999999.99", message = "薪资不能超过999999.99") + @DecimalMax(value = "999999.99", message = "薪资不能超过 999999.99") @Digits(integer = 6, fraction = 2, message = "薪资格式不正确") private BigDecimal salary; - + @Past(message = "生日必须是过去的日期") private LocalDate birthday; - + @Future(message = "合同到期日必须是未来的日期") private LocalDate contractEndDate; - + @AssertTrue(message = "必须同意用户协议") private Boolean agreeTerms; - - @Size(min = 1, max = 5, message = "技能数量必须在1-5之间") + + @Size(min = 1, max = 5, message = "技能数量必须在 1-5 之间") @Valid private List skills; - + // getter/setter... } ``` @@ -468,17 +477,19 @@ public class CompleteValidationDto { public class UserDto { // 分组接口定义 public interface BasicGroup {} + public interface AdvancedGroup {} + public interface StudentGroup {} + public interface TeacherGroup {} - + @NotBlank(message = "名称不能为空") private String name; - - @Max(value = 200, message = "高级组年龄必须小于等于200", groups = AdvancedGroup.class) + @Max(value = 200, message = "高级组年龄必须小于等于 200", groups = AdvancedGroup.class) private Integer age; - + // getter/setter... } ``` @@ -488,7 +499,7 @@ public class UserDto { @Validated(UserDto.AdvancedGroup.class) public class AdvancedUserService { public void processAdvancedUser(@Valid UserDto user) { - // 只会应用AdvancedGroup分组的校验规则 + // 只会应用 AdvancedGroup 分组的校验规则 } } ``` @@ -497,36 +508,35 @@ public class AdvancedUserService { ### 核心组件 -1. **ValidationHandler**:校验入口类,通过AOP方式拦截带有`@Validated`注解的类或方法,自动触发校验逻辑。 - -2. **Hibernate Validator**:底层使用Hibernate Validator作为校验引擎。 - +1. **ValidationHandler**:校验入口类,通过 AOP 方式拦截带有 `@Validated` 注解的类或方法,自动触发校验逻辑。 +2. **Hibernate Validator**:底层使用 Hibernate Validator 作为校验引擎。 3. **ConstraintViolationException**:校验失败时抛出的异常,包含详细的错误信息。 ### 校验流程 -1. 当调用带有`@Validated`注解的类的方法时,`ValidationHandler`会拦截该调用 +1. 当调用带有 `@Validated` 注解的类的方法时,`ValidationHandler` 会拦截该调用 2. 检查方法参数是否包含校验注解 -3. 使用Hibernate Validator对参数进行校验 -4. 如果校验失败,抛出`ConstraintViolationException`异常 +3. 使用 Hibernate Validator 对参数进行校验 +4. 如果校验失败,抛出 `ConstraintViolationException` 异常 5. 可通过全局异常处理器捕获并处理校验异常 - ## 12.3.4 版本差异 两个插件的主要差异: | 特性 | fit-hibernate-validation | fit-hibernate-validation-jakarta | -|------|-------------------------|----------------------------------| +|-------------|--------------------------|----------------------------------| | 校验规范 | javax.validation | jakarta.validation | -| Hibernate版本 | 6.2.5.Final | 9.0.1.Final | -| 适用环境 | 传统Java EE | Jakarta EE | +| Hibernate 版本 | 6.2.5.Final | 9.0.1.Final | +| 适用环境 | 传统 Java EE | Jakarta EE | | 包名空间 | javax.validation.* | jakarta.validation.* | 选择建议: -- 新项目推荐使用Jakarta版本 + +- 新项目推荐使用 Jakarta 版本 - 现有项目根据依赖情况选择对应版本 - 两个版本功能完全一致,仅包名空间不同 ## 12.3.5 校验的国际化 + 与校验扩展一样,需要手动处理报错信息中的内容,以完成国际化功能 \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index c5c4186e8..37d38a5af 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -6,6 +6,12 @@ package modelengine.fitframework.validation; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import jakarta.validation.executable.ExecutableValidator; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Scope; import modelengine.fitframework.aop.JoinPoint; @@ -23,13 +29,6 @@ import java.util.Arrays; import java.util.Set; -import jakarta.validation.ConstraintViolation; -import jakarta.validation.ConstraintViolationException; -import jakarta.validation.Validation; -import jakarta.validation.Validator; -import jakarta.validation.ValidatorFactory; -import jakarta.validation.executable.ExecutableValidator; - /** * 校验入口类。 *

@@ -55,14 +54,14 @@ public ValidationHandler() { } /** - * 方法参数校验处理 + * 方法参数校验处理。 * - * @param joinPoint 被拦截的连接点 {@link JoinPoint} - * @param validated 连接点上携带的校验注解 {@link Validated} + * @param joinPoint 被拦截的连接点 {@link JoinPoint}。 + * @param validated 连接点上携带的校验注解 {@link Validated}。 */ @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { - // 检查方法参数是否包含被 javax.validation.Constraint 标注的校验注解 + // 检查方法参数是否包含被 jakarta.validation.Constraint 标注的校验注解。 if (hasJakartaConstraintAnnotations(joinPoint.getMethod().getParameters())) { ExecutableValidator execVal = this.validator.forExecutables(); Set> result = execVal.validateParameters(joinPoint.getTarget(), @@ -82,65 +81,65 @@ public void close() { } /** - * 检查方法参数是否包含 jakarta.validation 校验注解 + * 检查方法参数是否包含 jakarta.validation 校验注解。 * - * @param parameters 方法参数数组 {@link Parameter[]} - * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false + * @param parameters 方法参数数组 {@link Parameter[]}。 + * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 */ private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { - return Arrays.stream(parameters) - .anyMatch(this::hasConstraintAnnotationsInParameter); + return Arrays.stream(parameters).anyMatch(this::hasConstraintAnnotationsInParameter); } /** - * 检查参数及其泛型类型参数是否包含校验注解 - * @param parameter 方法参数 {@link Parameter} - * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false + * 检查参数及其泛型类型参数是否包含校验注解。 + * + * @param parameter 方法参数 {@link Parameter}。 + * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 */ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { return hasConstraintAnnotationsInType(parameter.getAnnotatedType()); } /** - * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解 - * @param annotatedType 参数注解类型 {@link AnnotatedType} - * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false + * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解。 + * + * @param annotatedType 参数注解类型 {@link AnnotatedType}。 + * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 */ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { - // 检查当前类型上的注解 + // 检查当前类型上的注解。 if (Arrays.stream(annotatedType.getAnnotations()).anyMatch(this::isJakartaConstraintAnnotation)) { return true; } - - // 如果是参数化类型,递归检查类型参数 + + // 如果是参数化类型,递归检查类型参数。 if (annotatedType instanceof AnnotatedParameterizedType) { AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) annotatedType; return Arrays.stream(parameterizedType.getAnnotatedActualTypeArguments()) .anyMatch(this::hasConstraintAnnotationsInType); } - + return false; } /** - * 检查注解是否属于 jakarta.validation 注解 + * 检查注解是否属于 jakarta.validation 注解。 * * @param annotation 要检查的注解 {@link Annotation} - * @return 如果属于 jakarta.validation 注解则返回 true,否则返回 false + * @return 如果属于 jakarta.validation 注解则返回 true,否则返回 false {@code boolean}。 */ private boolean isJakartaConstraintAnnotation(Annotation annotation) { - // @Valid 注解检查 - if("jakarta.validation.Valid".equals(annotation.annotationType().getName())){ + // @Valid 注解检查。 + if ("jakarta.validation.Valid".equals(annotation.annotationType().getName())) { return true; } - // jakarta.validation.constraints, org.hibernate.validator.constraints 包下的注解检查 - // 通过 Constraint 注解检查当前注解是否为校验注解 + // jakarta.validation.constraints, org.hibernate.validator.constraints 包下的注解检查。 + // 通过 Constraint 注解检查当前注解是否为校验注解。 Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); - return Arrays.stream(metaAnnotations) - .anyMatch(metaAnnotation -> { - String packageName = metaAnnotation.annotationType().getPackage().getName(); - String className = metaAnnotation.annotationType().getSimpleName(); - return "jakarta.validation".equals(packageName) && "Constraint".equals(className); - }); + return Arrays.stream(metaAnnotations).anyMatch(metaAnnotation -> { + String packageName = metaAnnotation.annotationType().getPackage().getName(); + String className = metaAnnotation.annotationType().getSimpleName(); + return "jakarta.validation".equals(packageName) && "Constraint".equals(className); + }); } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java index 614a21be3..ce817a706 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java @@ -6,6 +6,8 @@ package modelengine.fitframework.validation; +import static org.assertj.core.api.Assertions.assertThat; + import modelengine.fit.http.client.HttpClassicClientResponse; import modelengine.fitframework.annotation.Fit; import modelengine.fitframework.test.annotation.MvcTest; @@ -15,6 +17,7 @@ import modelengine.fitframework.validation.data.Company; import modelengine.fitframework.validation.data.Employee; import modelengine.fitframework.validation.data.ValidationDataController; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -22,8 +25,6 @@ import java.io.IOException; import java.util.Collections; -import static org.assertj.core.api.Assertions.assertThat; - /** * {@link ValidationDataController} 的测试集。 * @@ -50,8 +51,9 @@ void teardown() throws IOException { void shouldOKWhenCreateValidCompany() { Employee validEmployee = new Employee("John", 25); Company validCompany = new Company(Collections.singletonList(validEmployee)); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/company/default").jsonEntity(validCompany).responseType(Void.class); + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/company/default") + .jsonEntity(validCompany) + .responseType(Void.class); this.response = this.mockMvc.perform(requestBuilder); assertThat(this.response.statusCode()).isEqualTo(200); } @@ -60,8 +62,9 @@ void shouldOKWhenCreateValidCompany() { @DisplayName("不合法 Company 对象校验") void shouldFailedWhenCreateInvalidCompany() { Company invalidCompany = new Company(null); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/company/default").jsonEntity(invalidCompany).responseType(Void.class); + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/company/default") + .jsonEntity(invalidCompany) + .responseType(Void.class); this.response = this.mockMvc.perform(requestBuilder); assertThat(this.response.statusCode()).isEqualTo(500); } @@ -71,8 +74,9 @@ void shouldFailedWhenCreateInvalidCompany() { void shouldOKWhenCreateValidCompanyWithGroup() { Employee validEmployee = new Employee("Jane", 30); Company validCompany = new Company(Collections.singletonList(validEmployee)); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/company/companyGroup").jsonEntity(validCompany).responseType(Void.class); + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/company/companyGroup") + .jsonEntity(validCompany) + .responseType(Void.class); this.response = this.mockMvc.perform(requestBuilder); assertThat(this.response.statusCode()).isEqualTo(200); } @@ -82,8 +86,9 @@ void shouldOKWhenCreateValidCompanyWithGroup() { void shouldFailedWhenCreateInvalidCompanyWithGroup() { Employee invalidEmployee = new Employee("", 15); Company invalidCompany = new Company(Collections.singletonList(invalidEmployee)); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/company/companyGroup").jsonEntity(invalidCompany).responseType(Void.class); + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/company/companyGroup") + .jsonEntity(invalidCompany) + .responseType(Void.class); this.response = this.mockMvc.perform(requestBuilder); assertThat(this.response.statusCode()).isEqualTo(500); } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 45b51c3db..aafc8b33a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -8,6 +8,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; +import jakarta.validation.ConstraintViolationException; import modelengine.fitframework.annotation.Fit; import modelengine.fitframework.test.annotation.FitTestWithJunit; import modelengine.fitframework.validation.data.Company; @@ -27,8 +28,6 @@ import java.util.List; import java.util.Map; -import jakarta.validation.ConstraintViolationException; - /** * {@link ValidationHandler} 的单元测试。 * @@ -37,11 +36,8 @@ */ @DisplayName("测试注解校验功能") @FitTestWithJunit(includeClasses = { - ValidateService.class, - ValidationHandler.class, - GroupValidateService.StudentValidateService.class, - GroupValidateService.TeacherValidateService.class, - GroupValidateService.AdvancedValidateService.class + ValidateService.class, ValidationHandler.class, GroupValidateService.StudentValidateService.class, + GroupValidateService.TeacherValidateService.class, GroupValidateService.AdvancedValidateService.class }) public class ValidationHandlerTest { @Fit @@ -73,184 +69,161 @@ void giveNestedClassThenValidateOk() { @Test @DisplayName("测试@NotNull注解") void testNotNullValidation() { - assertThatThrownBy(() -> this.validateService.testNotNull(null)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNotNull(null)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("不能为null"); } @Test @DisplayName("测试@NotEmpty注解") void testNotEmptyValidation() { - assertThatThrownBy(() -> this.validateService.testNotEmpty("")) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNotEmpty("")).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("不能为空"); } @Test @DisplayName("测试@NotBlank注解") void testNotBlankValidation() { - assertThatThrownBy(() -> this.validateService.testNotBlank(" ")) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNotBlank(" ")).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("不能为空"); } @Test @DisplayName("测试@Null注解") void testNullValidation() { - assertThatThrownBy(() -> this.validateService.testNull("not null")) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNull("not null")).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须为null"); } @Test @DisplayName("测试@Size注解-字符串") void testSizeStringValidation() { - assertThatThrownBy(() -> this.validateService.testSize("a")) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testSize("a")).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("个数必须在2和10之间"); } @Test @DisplayName("测试@Size注解-集合") void testSizeListValidation() { - assertThatThrownBy(() -> this.validateService.testSizeList(Arrays.asList("1", "2", "3", "4"))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("个数必须在1和3之间"); + assertThatThrownBy(() -> this.validateService.testSizeList(Arrays.asList("1", "2", "3", "4"))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("个数必须在1和3之间"); } @Test @DisplayName("测试@Min注解") void testMinValidation() { - assertThatThrownBy(() -> this.validateService.testMin(5)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testMin(5)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("最小不能小于10"); } @Test @DisplayName("测试@Max注解") void testMaxValidation() { - assertThatThrownBy(() -> this.validateService.testMax(150)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testMax(150)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("最大不能超过100"); } @Test @DisplayName("测试@DecimalMin注解") void testDecimalMinValidation() { - assertThatThrownBy(() -> this.validateService.testDecimalMin(new BigDecimal("5.0"))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须大于"); + assertThatThrownBy(() -> this.validateService.testDecimalMin(new BigDecimal("5.0"))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("必须大于"); } @Test @DisplayName("测试@DecimalMax注解") void testDecimalMaxValidation() { - assertThatThrownBy(() -> this.validateService.testDecimalMax(new BigDecimal("150.0"))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须小于"); + assertThatThrownBy(() -> this.validateService.testDecimalMax(new BigDecimal("150.0"))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("必须小于"); } @Test @DisplayName("测试@Positive注解") void testPositiveValidation() { - assertThatThrownBy(() -> this.validateService.testPositive(0)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testPositive(0)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须是正数"); } @Test @DisplayName("测试@PositiveOrZero注解") void testPositiveOrZeroValidation() { - assertThatThrownBy(() -> this.validateService.testPositiveOrZero(-1)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testPositiveOrZero(-1)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须是正数或零"); } @Test @DisplayName("测试@Negative注解") void testNegativeValidation() { - assertThatThrownBy(() -> this.validateService.testNegative(1)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNegative(1)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须是负数"); } @Test @DisplayName("测试@NegativeOrZero注解") void testNegativeOrZeroValidation() { - assertThatThrownBy(() -> this.validateService.testNegativeOrZero(1)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNegativeOrZero(1)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须是负数或零"); } @Test @DisplayName("测试@Digits注解") void testDigitsValidation() { - assertThatThrownBy(() -> this.validateService.testDigits(new BigDecimal("1234.567"))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("数字的值超出了允许范围"); + assertThatThrownBy(() -> this.validateService.testDigits(new BigDecimal("1234.567"))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("数字的值超出了允许范围"); } @Test @DisplayName("测试@Past注解") void testPastValidation() { - assertThatThrownBy(() -> this.validateService.testPast(LocalDate.now().plusDays(1))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要是一个过去的时间"); + assertThatThrownBy(() -> this.validateService.testPast(LocalDate.now().plusDays(1))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("需要是一个过去的时间"); } @Test @DisplayName("测试@PastOrPresent注解") void testPastOrPresentValidation() { - assertThatThrownBy(() -> this.validateService.testPastOrPresent(LocalDate.now().plusDays(1))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要是一个过去或现在的时间"); + assertThatThrownBy(() -> this.validateService.testPastOrPresent(LocalDate.now().plusDays(1))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("需要是一个过去或现在的时间"); } @Test @DisplayName("测试@Future注解") void testFutureValidation() { - assertThatThrownBy(() -> this.validateService.testFuture(LocalDate.now().minusDays(1))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要是一个将来的时间"); + assertThatThrownBy(() -> this.validateService.testFuture(LocalDate.now().minusDays(1))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("需要是一个将来的时间"); } @Test @DisplayName("测试@FutureOrPresent注解") void testFutureOrPresentValidation() { - assertThatThrownBy(() -> this.validateService.testFutureOrPresent(LocalDate.now().minusDays(1))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要是一个将来或现在的时间"); + assertThatThrownBy(() -> this.validateService.testFutureOrPresent(LocalDate.now().minusDays(1))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("需要是一个将来或现在的时间"); } @Test @DisplayName("测试@Pattern注解") void testPatternValidation() { - assertThatThrownBy(() -> this.validateService.testPattern("123")) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testPattern("123")).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("需要匹配正则表达式"); } @Test @DisplayName("测试@Email注解") void testEmailValidation() { - assertThatThrownBy(() -> this.validateService.testEmail("invalid-email")) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("不是一个合法的电子邮件地址"); + assertThatThrownBy(() -> this.validateService.testEmail("invalid-email")).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("不是一个合法的电子邮件地址"); } @Test @DisplayName("测试@AssertTrue注解") void testAssertTrueValidation() { - assertThatThrownBy(() -> this.validateService.testAssertTrue(false)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testAssertTrue(false)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("只能为true"); } @Test @DisplayName("测试@AssertFalse注解") void testAssertFalseValidation() { - assertThatThrownBy(() -> this.validateService.testAssertFalse(true)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testAssertFalse(true)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("只能为false"); } @@ -260,34 +233,31 @@ void testComplexObjectValidation() { ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(null); // 违反@NotNull invalidData.setAge(200); // 违反@Max(150) - - assertThatThrownBy(() -> this.validateService.testValidObject(invalidData)) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("名称不能为空"); + + assertThatThrownBy(() -> this.validateService.testValidObject(invalidData)).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("名称不能为空"); } @Test @DisplayName("校验数据类,该数据类的 Constraint 字段会被校验,其余字段不会被校验") public void givenFieldsWithConstraintAnnotationThenValidateHappened() { Employee invalidEmployee = new Employee("", 150); // 空名字,年龄超限 - assertThatThrownBy(() -> validateService.validateEmployee(invalidEmployee)) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("不能为空"); + assertThatThrownBy(() -> validateService.validateEmployee(invalidEmployee)).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("不能为空"); } @Test @DisplayName("校验方法参数,该方法的 Constraint 参数会被校验,其余参数不会被校验") public void givenParametersWithConstraintAnnotationThenValidateHappened() { - assertThatThrownBy(() -> validateService.validateAge(-1)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> validateService.validateAge(-1)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须是正数"); } @Test @DisplayName("校验多个参数") public void givenMultipleParametersThenValidateHappened() { - assertThatThrownBy(() -> validateService.validateNameAndAge("", -1)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateNameAndAge("", + -1)).isInstanceOf(ConstraintViolationException.class); } @Test @@ -296,9 +266,8 @@ public void givenFieldsThenSameGroupValidateHappened() { ValidationTestData data = new ValidationTestData(); data.setAge(300); // 违反高级分组的约束 data.setName(""); // 违反默认分组约束 - - assertThatThrownBy(() -> validateService.validateAdvancedGroup(data)) - .isInstanceOf(ConstraintViolationException.class) + + assertThatThrownBy(() -> validateService.validateAdvancedGroup(data)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("高级组年龄必须小于等于200"); } @@ -306,8 +275,7 @@ public void givenFieldsThenSameGroupValidateHappened() { @DisplayName("校验方法参数,分组约束测试") public void givenParametersThenGroupValidateHappened() { // 测试学生年龄验证 - 现在会抛出异常,因为使用了学生分组 - assertThatThrownBy(() -> validateService.validateStudentAge(25)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> validateService.validateStudentAge(25)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("范围要在7~20之内"); } @@ -315,8 +283,7 @@ public void givenParametersThenGroupValidateHappened() { @DisplayName("校验方法参数,教师年龄验证测试") public void givenParametersThenTeacherGroupValidateNotHappened() { // 测试教师年龄验证 - 现在会抛出异常,因为使用了教师分组 - assertThatThrownBy(() -> validateService.validateTeacherAge(15)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> validateService.validateTeacherAge(15)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("范围要在22~65之内"); } @@ -326,9 +293,8 @@ void shouldReturnMsgWhenValidateCompany() { Employee invalidEmployee1 = new Employee("", 17); // 空名字,年龄不足 Employee invalidEmployee2 = new Employee("John", 150); // 年龄超限 Company company = new Company(Arrays.asList(invalidEmployee1, invalidEmployee2)); - - assertThatThrownBy(() -> validateService.validateCompany(company)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.validateCompany(company)).isInstanceOf(ConstraintViolationException.class); } @Test @@ -338,9 +304,9 @@ void shouldReturnMsgWhenValidateList() { Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); List employees = Arrays.asList(validEmployee, invalidEmployee1, invalidEmployee2); - - assertThatThrownBy(() -> validateService.validateEmployeeList(employees)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.validateEmployeeList(employees)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -350,13 +316,13 @@ void shouldReturnMsgWhenValidateListInList() { Employee validEmployee2 = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); - + List employeeList1 = Arrays.asList(validEmployee1, invalidEmployee1); List employeeList2 = Arrays.asList(validEmployee2, invalidEmployee2); List> nestedList = Arrays.asList(employeeList1, employeeList2); - assertThatThrownBy(() -> validateService.validateNestedEmployeeList(nestedList)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateNestedEmployeeList(nestedList)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -365,14 +331,14 @@ void shouldReturnMsgWhenValidateMapSimple() { Employee validEmployee = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); - + Map employeeMap = new HashMap<>(); employeeMap.put("1", validEmployee); employeeMap.put("2", invalidEmployee1); employeeMap.put("3", invalidEmployee2); - - assertThatThrownBy(() -> validateService.validateEmployeeMap(employeeMap)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.validateEmployeeMap(employeeMap)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -380,21 +346,20 @@ void shouldReturnMsgWhenValidateMapSimple() { void shouldReturnMsgWhenValidateMapObj() { Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); - + ValidationTestData validData = new ValidationTestData(); validData.setName("Test"); validData.setAge(25); - + ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(""); invalidData.setAge(-1); - + Map map = new HashMap<>(); map.put(validEmployee, validData); map.put(invalidEmployee, invalidData); - - assertThatThrownBy(() -> validateService.validateEmployeeDataMap(map)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.validateEmployeeDataMap(map)).isInstanceOf(ConstraintViolationException.class); } @Test @@ -402,25 +367,25 @@ void shouldReturnMsgWhenValidateMapObj() { void shouldReturnMsgWhenValidateMapInMap() { Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); - + ValidationTestData validData = new ValidationTestData(); validData.setName("Test"); validData.setAge(25); - + ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(""); invalidData.setAge(-1); - + Map innerMap = new HashMap<>(); innerMap.put("valid", validData); innerMap.put("invalid", invalidData); - + Map> nestedMap = new HashMap<>(); nestedMap.put(validEmployee, innerMap); nestedMap.put(invalidEmployee, innerMap); - assertThatThrownBy(() -> validateService.validateNestedEmployeeDataMap(nestedMap)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateNestedEmployeeDataMap(nestedMap)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -429,19 +394,19 @@ void shouldReturnMsgWhenValidateMapInList() { Employee validEmployee = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); - + Map map1 = new HashMap<>(); map1.put("valid", validEmployee); map1.put("invalid1", invalidEmployee1); - + Map map2 = new HashMap<>(); map2.put("valid", validEmployee); map2.put("invalid2", invalidEmployee2); - + List> listOfMaps = Arrays.asList(map1, map2); - assertThatThrownBy(() -> validateService.validateEmployeeMapList(listOfMaps)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateEmployeeMapList(listOfMaps)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -449,24 +414,24 @@ void shouldReturnMsgWhenValidateMapInList() { void shouldReturnMsgWhenValidateListInMap() { Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); - + ValidationTestData validData = new ValidationTestData(); validData.setName("Test"); validData.setAge(25); - + ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(""); invalidData.setAge(-1); - + List dataList1 = Arrays.asList(validData, invalidData); List dataList2 = Arrays.asList(validData); - + Map> map = new HashMap<>(); map.put(validEmployee, dataList1); map.put(invalidEmployee, dataList2); - assertThatThrownBy(() -> validateService.validateEmployeeDataListMap(map)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateEmployeeDataListMap(map)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -475,9 +440,9 @@ void shouldReturnMsgWhenValidateListComplex() { Employee invalidEmployee = new Employee("", 17); Company invalidCompany = new Company(Arrays.asList(invalidEmployee)); List companies = Arrays.asList(invalidCompany); - - assertThatThrownBy(() -> validateService.validateCompanyList(companies)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.validateCompanyList(companies)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -545,7 +510,7 @@ void testValidComplexObject() { validData.setQuantity(10); validData.setDiscount(new BigDecimal("-5.0")); validData.setAgreed(true); - + validateService.testValidObject(validData); } @@ -556,39 +521,36 @@ void testMultipleValidationFailures() { invalidData.setName(""); // 违反@NotBlank invalidData.setAge(-1); // 违反@Min(0) invalidData.setQuantity(-10); // 违反@Positive - - assertThatThrownBy(() -> validateService.testValidObject(invalidData)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.testValidObject(invalidData)).isInstanceOf(ConstraintViolationException.class); } @Test @DisplayName("测试混合原始类型和对象校验") void testMixedPrimitiveAndObjectValidation() { Employee invalidEmployee = new Employee("", 17); - assertThatThrownBy(() -> validateService.validateMixed(-1, invalidEmployee)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateMixed(-1, invalidEmployee)).isInstanceOf( + ConstraintViolationException.class); } @Test @DisplayName("测试空集合和null值混合") void testEmptyCollectionAndNullMixed() { - assertThatThrownBy(() -> validateService.validateMixedCollections(null, Collections.emptyList())) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateMixedCollections(null, Collections.emptyList())).isInstanceOf( + ConstraintViolationException.class); } @Test @DisplayName("测试@Range注解-最小值验证") void testRangeMinValidation() { - assertThatThrownBy(() -> this.validateService.testRange(5)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testRange(5)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("需要在10和100之间"); } @Test @DisplayName("测试@Range注解-最大值验证") void testRangeMaxValidation() { - assertThatThrownBy(() -> this.validateService.testRange(150)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testRange(150)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("需要在10和100之间"); } @@ -613,9 +575,8 @@ void testRangeValidValue() { @Test @DisplayName("测试@Range注解-BigDecimal类型") void testRangeBigDecimalValidation() { - assertThatThrownBy(() -> this.validateService.testRangeBigDecimal(new BigDecimal("5.5"))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要在10和100之间"); + assertThatThrownBy(() -> this.validateService.testRangeBigDecimal(new BigDecimal("5.5"))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("需要在10和100之间"); } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java index 824a967d8..17f9e2447 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -6,10 +6,9 @@ package modelengine.fitframework.validation.data; - - import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; + import java.util.List; /** @@ -22,9 +21,9 @@ public class Company { @NotNull @Valid private List employees; - + public Company() {} - + public Company(List employees) { this.employees = employees; } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index a3c936667..06f97c6a7 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -6,13 +6,12 @@ package modelengine.fitframework.validation.data; -import modelengine.fitframework.annotation.Component; -import modelengine.fitframework.log.Logger; -import modelengine.fitframework.validation.Validated; - import jakarta.validation.Valid; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.log.Logger; +import modelengine.fitframework.validation.Validated; /** * 表示测试用分组校验服务。 @@ -28,8 +27,10 @@ public class GroupValidateService { @Component @Validated(ValidationTestData.StudentGroup.class) public static class StudentValidateService { - public void validateStudentAge(@Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) - @Max(value = 20, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) int age) { + public void validateStudentAge( + @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) @Max( + value = 20, message = "范围要在7~20之内", + groups = ValidationTestData.StudentGroup.class) int age) { LOG.debug("Validating student age: {}", age); } } @@ -38,8 +39,10 @@ public void validateStudentAge(@Min(value = 7, message = "范围要在7~20之内 @Component @Validated(ValidationTestData.TeacherGroup.class) public static class TeacherValidateService { - public void validateTeacherAge(@Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) - @Max(value = 65, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) int age) { + public void validateTeacherAge( + @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) @Max( + value = 65, message = "范围要在22~65之内", + groups = ValidationTestData.TeacherGroup.class) int age) { LOG.debug("Validating teacher age: {}", age); } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index 185f465aa..de4171580 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -6,16 +6,36 @@ package modelengine.fitframework.validation.data; +import jakarta.validation.Valid; +import jakarta.validation.constraints.AssertFalse; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Digits; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Future; +import jakarta.validation.constraints.FutureOrPresent; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Negative; +import jakarta.validation.constraints.NegativeOrZero; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Past; +import jakarta.validation.constraints.PastOrPresent; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import jakarta.validation.constraints.Size; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Fit; import modelengine.fitframework.log.Logger; import modelengine.fitframework.validation.Validated; -import org.hibernate.validator.constraints.Range; - +import org.hibernate.validator.constraints.Range; -import jakarta.validation.Valid; -import jakarta.validation.constraints.*; import java.math.BigDecimal; import java.time.LocalDate; import java.util.List; @@ -34,10 +54,10 @@ public class ValidateService { @Fit private GroupValidateService.StudentValidateService studentValidateService; - + @Fit private GroupValidateService.TeacherValidateService teacherValidateService; - + @Fit private GroupValidateService.AdvancedValidateService advancedValidateService; @@ -53,7 +73,7 @@ public void foo0(@Positive(message = "必须是正数") int num) { /** * 测试结构体类型。 * - * @param employee 表示输入的 {@code Employee}。 + * @param employee 表示输入的 {@link Employee}。 */ public void foo1(@Valid Employee employee) { LOG.debug("{}", employee); @@ -62,7 +82,7 @@ public void foo1(@Valid Employee employee) { /** * 测试嵌套类型。 * - * @param company 表示输入的 {@code Company}。 + * @param company 表示输入的 {@link Company}。 */ public void foo2(@Valid Company company) { LOG.debug("{}", company); @@ -232,7 +252,7 @@ public void testAssertFalse(@AssertFalse boolean value) {} /** * 测试 Valid 对象验证。 * - * @param data 表示输入的 {@code ValidationTestData}。 + * @param data 表示输入的 {@link ValidationTestData}。 */ public void testValidObject(@Valid ValidationTestData data) {} @@ -253,7 +273,7 @@ public void testRangeBigDecimal(@Range(min = 10, max = 100, message = "需要在 /** * 验证 Employee 对象。 * - * @param employee 表示输入的 {@code Employee}。 + * @param employee 表示输入的 {@link Employee}。 */ public void validateEmployee(@Valid Employee employee) { LOG.debug("Validating employee: {}", employee); @@ -281,7 +301,7 @@ public void validateNameAndAge(@NotBlank String name, @Positive int age) { /** * 验证高级分组数据。 * - * @param data 表示输入的 {@code ValidationTestData}。 + * @param data 表示输入的 {@link ValidationTestData}。 */ public void validateAdvancedGroup(ValidationTestData data) { if (advancedValidateService != null) { @@ -314,7 +334,7 @@ public void validateTeacherAge(int age) { /** * 验证公司对象。 * - * @param company 表示输入的 {@code Company}。 + * @param company 表示输入的 {@link Company}。 */ public void validateCompany(@Valid Company company) { LOG.debug("Validating company: {}", company); @@ -323,7 +343,7 @@ public void validateCompany(@Valid Company company) { /** * 验证员工列表。 * - * @param employees 表示输入的 {@code List}。 + * @param employees 表示输入的 {@link List}。 */ public void validateEmployeeList(List<@Valid Employee> employees) { LOG.debug("Validating employee list: {}", employees); @@ -332,7 +352,7 @@ public void validateEmployeeList(List<@Valid Employee> employees) { /** * 验证嵌套员工列表。 * - * @param nestedList 表示输入的 {@code List>}。 + * @param nestedList 表示输入的 {@link List>}。 */ public void validateNestedEmployeeList(List> nestedList) { LOG.debug("Validating nested employee list: {}", nestedList); @@ -341,7 +361,7 @@ public void validateNestedEmployeeList(List> nestedList) { /** * 验证员工映射。 * - * @param employeeMap 表示输入的 {@code Map}。 + * @param employeeMap 表示输入的 {@link Map}。 */ public void validateEmployeeMap(@Valid Map employeeMap) { LOG.debug("Validating employee map: {}", employeeMap); @@ -350,7 +370,7 @@ public void validateEmployeeMap(@Valid Map employeeMap) { /** * 验证员工数据映射。 * - * @param map 表示输入的 {@code Map}。 + * @param map 表示输入的 {@link Map}。 */ public void validateEmployeeDataMap(@Valid Map map) { LOG.debug("Validating employee data map: {}", map); @@ -359,7 +379,7 @@ public void validateEmployeeDataMap(@Valid Map map /** * 验证嵌套员工数据映射。 * - * @param nestedMap 表示输入的 {@code Map>}。 + * @param nestedMap 表示输入的 {@link Map>}。 */ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map> nestedMap) { LOG.debug("Validating nested employee data map: {}", nestedMap); @@ -368,7 +388,7 @@ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map>}。 + * @param listOfMaps 表示输入的 {@link List>}。 */ public void validateEmployeeMapList(List> listOfMaps) { LOG.debug("Validating employee map list: {}", listOfMaps); @@ -377,7 +397,7 @@ public void validateEmployeeMapList(List> listOfMap /** * 验证员工数据列表映射。 * - * @param map 表示输入的 {@code Map>}。 + * @param map 表示输入的 {@link Map>}。 */ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { LOG.debug("Validating employee data list map: {}", map); @@ -386,7 +406,7 @@ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid Validat /** * 验证公司列表。 * - * @param companies 表示输入的 {@code List}。 + * @param companies 表示输入的 {@link List}。 */ public void validateCompanyList(@Valid List companies) { LOG.debug("Validating company list: {}", companies); @@ -396,7 +416,7 @@ public void validateCompanyList(@Valid List companies) { * 验证混合类型数据。 * * @param value 表示输入的 {@code int}。 - * @param employee 表示输入的 {@code Employee}。 + * @param employee 表示输入的 {@link Employee}。 */ public void validateMixed(@Positive int value, @Valid Employee employee) { LOG.debug("Validating mixed primitive {} and object {}", value, employee); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java index f0c62886d..631451c3f 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationDataController.java @@ -6,14 +6,13 @@ package modelengine.fitframework.validation.data; +import jakarta.validation.Valid; import modelengine.fit.http.annotation.PostMapping; import modelengine.fit.http.annotation.RequestBody; import modelengine.fit.http.annotation.RequestMapping; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.validation.Validated; -import jakarta.validation.Valid; - /** * 表示评估注解验证数据接口集。 * diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index 5f345b01b..dbf40cfaf 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -6,9 +6,14 @@ package modelengine.fitframework.validation.data; -import jakarta.validation.constraints.*; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Negative; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Positive; + import java.math.BigDecimal; -import java.time.LocalDate; /** * 测试用的复杂验证数据类。 @@ -20,7 +25,9 @@ public class ValidationTestData { // 分组接口定义 public interface AdvancedGroup {} + public interface StudentGroup {} + public interface TeacherGroup {} @NotBlank(message = "名称不能为空") diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 0c951e8a3..09eafd88c 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -55,14 +55,14 @@ public class ValidationHandler implements AutoCloseable { } /** - * 方法参数校验处理 + * 方法参数校验处理。 * - * @param joinPoint 被拦截的连接点 {@link JoinPoint} - * @param validated 连接点上携带的校验注解 {@link Validated} + * @param joinPoint 被拦截的连接点 {@link JoinPoint}。 + * @param validated 连接点上携带的校验注解 {@link Validated}。 */ @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { - // 检查方法参数是否包含被 jakarta.validation.Constraint 标注的校验注解 + // 检查方法参数是否包含被 javax.validation.Constraint 标注的校验注解。 if (hasJavaxConstraintAnnotations(joinPoint.getMethod().getParameters())) { ExecutableValidator execVal = this.validator.forExecutables(); Set> result = execVal.validateParameters(joinPoint.getTarget(), @@ -82,65 +82,65 @@ public void close() { } /** - * 检查方法参数是否包含 javax.validation 校验注解 + * 检查方法参数是否包含 javax.validation 校验注解。 * - * @param parameters 方法参数数组 {@link Parameter[]} - * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false + * @param parameters 方法参数数组 {@link Parameter[]}。 + * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 */ private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { - return Arrays.stream(parameters) - .anyMatch(this::hasConstraintAnnotationsInParameter); + return Arrays.stream(parameters).anyMatch(this::hasConstraintAnnotationsInParameter); } /** - * 检查参数及其泛型类型参数是否包含校验注解 - * @param parameter 方法参数数组 {@link Parameter} - * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false + * 检查参数及其泛型类型参数是否包含校验注解。 + * + * @param parameter 方法参数数组 {@link Parameter}。 + * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 */ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { return hasConstraintAnnotationsInType(parameter.getAnnotatedType()); } /** - * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解 - * @param annotatedType 参数注解类型 {@link AnnotatedType} - * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false + * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解。 + * + * @param annotatedType 参数注解类型 {@link AnnotatedType}。 + * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 */ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { - // 检查当前类型上的注解 + // 检查当前类型上的注解。 if (annotatedType.getAnnotations().length > 0) { return Arrays.stream(annotatedType.getAnnotations()).anyMatch(this::isJavaxConstraintAnnotation); } - - // 如果是参数化类型,递归检查类型参数 + + // 如果是参数化类型,递归检查类型参数。 if (annotatedType instanceof AnnotatedParameterizedType) { AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) annotatedType; return Arrays.stream(parameterizedType.getAnnotatedActualTypeArguments()) .anyMatch(this::hasConstraintAnnotationsInType); } - + return false; } /** - * 检查注解是否属于 javax.validation 注解 + * 检查注解是否属于 javax.validation 注解。 * - * @param annotation 要检查的注解 {@link Annotation} - * @return 如果属于 javax.validation 注解则返回 true,否则返回 false + * @param annotation 要检查的注解 {@link Annotation}。 + * @return 如果属于 javax.validation 注解则返回 true,否则返回 false {@code boolean}。 */ private boolean isJavaxConstraintAnnotation(Annotation annotation) { - // @Valid 注解检查 - if(annotation.annotationType().getName().equals("javax.validation.Valid")){ + // @Valid 注解检查。 + if (annotation.annotationType().getName().equals("javax.validation.Valid")) { return true; } - // javax.validation.constraints, org.hibernate.validator.constraints 包下的注解检查 - // 通过 Constraint 注解检查当前注解是否为校验注解 + // javax.validation.constraints, org.hibernate.validator.constraints 包下的注解检查。 + // 通过 Constraint 注解检查当前注解是否为校验注解。 Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); - return Arrays.stream(metaAnnotations) - .anyMatch(metaAnnotation -> { - String packageName = metaAnnotation.annotationType().getPackage().getName(); - String className = metaAnnotation.annotationType().getSimpleName(); - return "javax.validation".equals(packageName) && "Constraint".equals(className); - }); + return Arrays.stream(metaAnnotations).anyMatch(metaAnnotation -> { + String packageName = metaAnnotation.annotationType().getPackage().getName(); + String className = metaAnnotation.annotationType().getSimpleName(); + return "javax.validation".equals(packageName) && "Constraint".equals(className); + }); } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java index 614a21be3..ce817a706 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationDataControllerTest.java @@ -6,6 +6,8 @@ package modelengine.fitframework.validation; +import static org.assertj.core.api.Assertions.assertThat; + import modelengine.fit.http.client.HttpClassicClientResponse; import modelengine.fitframework.annotation.Fit; import modelengine.fitframework.test.annotation.MvcTest; @@ -15,6 +17,7 @@ import modelengine.fitframework.validation.data.Company; import modelengine.fitframework.validation.data.Employee; import modelengine.fitframework.validation.data.ValidationDataController; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -22,8 +25,6 @@ import java.io.IOException; import java.util.Collections; -import static org.assertj.core.api.Assertions.assertThat; - /** * {@link ValidationDataController} 的测试集。 * @@ -50,8 +51,9 @@ void teardown() throws IOException { void shouldOKWhenCreateValidCompany() { Employee validEmployee = new Employee("John", 25); Company validCompany = new Company(Collections.singletonList(validEmployee)); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/company/default").jsonEntity(validCompany).responseType(Void.class); + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/company/default") + .jsonEntity(validCompany) + .responseType(Void.class); this.response = this.mockMvc.perform(requestBuilder); assertThat(this.response.statusCode()).isEqualTo(200); } @@ -60,8 +62,9 @@ void shouldOKWhenCreateValidCompany() { @DisplayName("不合法 Company 对象校验") void shouldFailedWhenCreateInvalidCompany() { Company invalidCompany = new Company(null); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/company/default").jsonEntity(invalidCompany).responseType(Void.class); + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/company/default") + .jsonEntity(invalidCompany) + .responseType(Void.class); this.response = this.mockMvc.perform(requestBuilder); assertThat(this.response.statusCode()).isEqualTo(500); } @@ -71,8 +74,9 @@ void shouldFailedWhenCreateInvalidCompany() { void shouldOKWhenCreateValidCompanyWithGroup() { Employee validEmployee = new Employee("Jane", 30); Company validCompany = new Company(Collections.singletonList(validEmployee)); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/company/companyGroup").jsonEntity(validCompany).responseType(Void.class); + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/company/companyGroup") + .jsonEntity(validCompany) + .responseType(Void.class); this.response = this.mockMvc.perform(requestBuilder); assertThat(this.response.statusCode()).isEqualTo(200); } @@ -82,8 +86,9 @@ void shouldOKWhenCreateValidCompanyWithGroup() { void shouldFailedWhenCreateInvalidCompanyWithGroup() { Employee invalidEmployee = new Employee("", 15); Company invalidCompany = new Company(Collections.singletonList(invalidEmployee)); - MockRequestBuilder requestBuilder = - MockMvcRequestBuilders.post("/validation/company/companyGroup").jsonEntity(invalidCompany).responseType(Void.class); + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/company/companyGroup") + .jsonEntity(invalidCompany) + .responseType(Void.class); this.response = this.mockMvc.perform(requestBuilder); assertThat(this.response.statusCode()).isEqualTo(500); } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 70a598db1..fc07c3e88 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -37,11 +37,8 @@ */ @DisplayName("测试注解校验功能") @FitTestWithJunit(includeClasses = { - ValidateService.class, - ValidationHandler.class, - GroupValidateService.StudentValidateService.class, - GroupValidateService.TeacherValidateService.class, - GroupValidateService.AdvancedValidateService.class + ValidateService.class, ValidationHandler.class, GroupValidateService.StudentValidateService.class, + GroupValidateService.TeacherValidateService.class, GroupValidateService.AdvancedValidateService.class }) public class ValidationHandlerTest { @Fit @@ -73,184 +70,161 @@ void giveNestedClassThenValidateOk() { @Test @DisplayName("测试@NotNull注解") void testNotNullValidation() { - assertThatThrownBy(() -> this.validateService.testNotNull(null)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNotNull(null)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("不能为null"); } @Test @DisplayName("测试@NotEmpty注解") void testNotEmptyValidation() { - assertThatThrownBy(() -> this.validateService.testNotEmpty("")) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNotEmpty("")).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("不能为空"); } @Test @DisplayName("测试@NotBlank注解") void testNotBlankValidation() { - assertThatThrownBy(() -> this.validateService.testNotBlank(" ")) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNotBlank(" ")).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("不能为空"); } @Test @DisplayName("测试@Null注解") void testNullValidation() { - assertThatThrownBy(() -> this.validateService.testNull("not null")) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNull("not null")).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须为null"); } @Test @DisplayName("测试@Size注解-字符串") void testSizeStringValidation() { - assertThatThrownBy(() -> this.validateService.testSize("a")) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testSize("a")).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("个数必须在2和10之间"); } @Test @DisplayName("测试@Size注解-集合") void testSizeListValidation() { - assertThatThrownBy(() -> this.validateService.testSizeList(Arrays.asList("1", "2", "3", "4"))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("个数必须在1和3之间"); + assertThatThrownBy(() -> this.validateService.testSizeList(Arrays.asList("1", "2", "3", "4"))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("个数必须在1和3之间"); } @Test @DisplayName("测试@Min注解") void testMinValidation() { - assertThatThrownBy(() -> this.validateService.testMin(5)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testMin(5)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("最小不能小于10"); } @Test @DisplayName("测试@Max注解") void testMaxValidation() { - assertThatThrownBy(() -> this.validateService.testMax(150)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testMax(150)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("最大不能超过100"); } @Test @DisplayName("测试@DecimalMin注解") void testDecimalMinValidation() { - assertThatThrownBy(() -> this.validateService.testDecimalMin(new BigDecimal("5.0"))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须大于"); + assertThatThrownBy(() -> this.validateService.testDecimalMin(new BigDecimal("5.0"))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("必须大于"); } @Test @DisplayName("测试@DecimalMax注解") void testDecimalMaxValidation() { - assertThatThrownBy(() -> this.validateService.testDecimalMax(new BigDecimal("150.0"))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须小于"); + assertThatThrownBy(() -> this.validateService.testDecimalMax(new BigDecimal("150.0"))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("必须小于"); } @Test @DisplayName("测试@Positive注解") void testPositiveValidation() { - assertThatThrownBy(() -> this.validateService.testPositive(0)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testPositive(0)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须是正数"); } @Test @DisplayName("测试@PositiveOrZero注解") void testPositiveOrZeroValidation() { - assertThatThrownBy(() -> this.validateService.testPositiveOrZero(-1)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testPositiveOrZero(-1)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须是正数或零"); } @Test @DisplayName("测试@Negative注解") void testNegativeValidation() { - assertThatThrownBy(() -> this.validateService.testNegative(1)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNegative(1)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须是负数"); } @Test @DisplayName("测试@NegativeOrZero注解") void testNegativeOrZeroValidation() { - assertThatThrownBy(() -> this.validateService.testNegativeOrZero(1)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testNegativeOrZero(1)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须是负数或零"); } @Test @DisplayName("测试@Digits注解") void testDigitsValidation() { - assertThatThrownBy(() -> this.validateService.testDigits(new BigDecimal("1234.567"))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("数字的值超出了允许范围"); + assertThatThrownBy(() -> this.validateService.testDigits(new BigDecimal("1234.567"))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("数字的值超出了允许范围"); } @Test @DisplayName("测试@Past注解") void testPastValidation() { - assertThatThrownBy(() -> this.validateService.testPast(LocalDate.now().plusDays(1))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要是一个过去的时间"); + assertThatThrownBy(() -> this.validateService.testPast(LocalDate.now().plusDays(1))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("需要是一个过去的时间"); } @Test @DisplayName("测试@PastOrPresent注解") void testPastOrPresentValidation() { - assertThatThrownBy(() -> this.validateService.testPastOrPresent(LocalDate.now().plusDays(1))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要是一个过去或现在的时间"); + assertThatThrownBy(() -> this.validateService.testPastOrPresent(LocalDate.now().plusDays(1))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("需要是一个过去或现在的时间"); } @Test @DisplayName("测试@Future注解") void testFutureValidation() { - assertThatThrownBy(() -> this.validateService.testFuture(LocalDate.now().minusDays(1))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要是一个将来的时间"); + assertThatThrownBy(() -> this.validateService.testFuture(LocalDate.now().minusDays(1))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("需要是一个将来的时间"); } @Test @DisplayName("测试@FutureOrPresent注解") void testFutureOrPresentValidation() { - assertThatThrownBy(() -> this.validateService.testFutureOrPresent(LocalDate.now().minusDays(1))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要是一个将来或现在的时间"); + assertThatThrownBy(() -> this.validateService.testFutureOrPresent(LocalDate.now().minusDays(1))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("需要是一个将来或现在的时间"); } @Test @DisplayName("测试@Pattern注解") void testPatternValidation() { - assertThatThrownBy(() -> this.validateService.testPattern("123")) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testPattern("123")).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("需要匹配正则表达式"); } @Test @DisplayName("测试@Email注解") void testEmailValidation() { - assertThatThrownBy(() -> this.validateService.testEmail("invalid-email")) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("不是一个合法的电子邮件地址"); + assertThatThrownBy(() -> this.validateService.testEmail("invalid-email")).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("不是一个合法的电子邮件地址"); } @Test @DisplayName("测试@AssertTrue注解") void testAssertTrueValidation() { - assertThatThrownBy(() -> this.validateService.testAssertTrue(false)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testAssertTrue(false)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("只能为true"); } @Test @DisplayName("测试@AssertFalse注解") void testAssertFalseValidation() { - assertThatThrownBy(() -> this.validateService.testAssertFalse(true)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testAssertFalse(true)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("只能为false"); } @@ -260,34 +234,31 @@ void testComplexObjectValidation() { ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(null); // 违反@NotNull invalidData.setAge(200); // 违反@Max(150) - - assertThatThrownBy(() -> this.validateService.testValidObject(invalidData)) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("名称不能为空"); + + assertThatThrownBy(() -> this.validateService.testValidObject(invalidData)).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("名称不能为空"); } @Test @DisplayName("校验数据类,该数据类的 Constraint 字段会被校验,其余字段不会被校验") public void givenFieldsWithConstraintAnnotationThenValidateHappened() { Employee invalidEmployee = new Employee("", 150); // 空名字,年龄超限 - assertThatThrownBy(() -> validateService.validateEmployee(invalidEmployee)) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("不能为空"); + assertThatThrownBy(() -> validateService.validateEmployee(invalidEmployee)).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("不能为空"); } @Test @DisplayName("校验方法参数,该方法的 Constraint 参数会被校验,其余参数不会被校验") public void givenParametersWithConstraintAnnotationThenValidateHappened() { - assertThatThrownBy(() -> validateService.validateAge(-1)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> validateService.validateAge(-1)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("必须是正数"); } @Test @DisplayName("校验多个参数") public void givenMultipleParametersThenValidateHappened() { - assertThatThrownBy(() -> validateService.validateNameAndAge("", -1)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateNameAndAge("", + -1)).isInstanceOf(ConstraintViolationException.class); } @Test @@ -296,9 +267,8 @@ public void givenFieldsThenSameGroupValidateHappened() { ValidationTestData data = new ValidationTestData(); data.setAge(300); // 违反高级分组的约束 data.setName(""); // 违反默认分组约束 - - assertThatThrownBy(() -> validateService.validateAdvancedGroup(data)) - .isInstanceOf(ConstraintViolationException.class) + + assertThatThrownBy(() -> validateService.validateAdvancedGroup(data)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("高级组年龄必须小于等于200"); } @@ -306,8 +276,7 @@ public void givenFieldsThenSameGroupValidateHappened() { @DisplayName("校验方法参数,分组约束测试") public void givenParametersThenGroupValidateHappened() { // 测试学生年龄验证 - 现在会抛出异常,因为使用了学生分组 - assertThatThrownBy(() -> validateService.validateStudentAge(25)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> validateService.validateStudentAge(25)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("范围要在7~20之内"); } @@ -315,8 +284,7 @@ public void givenParametersThenGroupValidateHappened() { @DisplayName("校验方法参数,教师年龄验证测试") public void givenParametersThenTeacherGroupValidateNotHappened() { // 测试教师年龄验证 - 现在会抛出异常,因为使用了教师分组 - assertThatThrownBy(() -> validateService.validateTeacherAge(15)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> validateService.validateTeacherAge(15)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("范围要在22~65之内"); } @@ -326,9 +294,8 @@ void shouldReturnMsgWhenValidateCompany() { Employee invalidEmployee1 = new Employee("", 17); // 空名字,年龄不足 Employee invalidEmployee2 = new Employee("John", 150); // 年龄超限 Company company = new Company(Arrays.asList(invalidEmployee1, invalidEmployee2)); - - assertThatThrownBy(() -> validateService.validateCompany(company)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.validateCompany(company)).isInstanceOf(ConstraintViolationException.class); } @Test @@ -338,9 +305,9 @@ void shouldReturnMsgWhenValidateList() { Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); List employees = Arrays.asList(validEmployee, invalidEmployee1, invalidEmployee2); - - assertThatThrownBy(() -> validateService.validateEmployeeList(employees)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.validateEmployeeList(employees)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -350,13 +317,13 @@ void shouldReturnMsgWhenValidateListInList() { Employee validEmployee2 = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); - + List employeeList1 = Arrays.asList(validEmployee1, invalidEmployee1); List employeeList2 = Arrays.asList(validEmployee2, invalidEmployee2); List> nestedList = Arrays.asList(employeeList1, employeeList2); - assertThatThrownBy(() -> validateService.validateNestedEmployeeList(nestedList)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateNestedEmployeeList(nestedList)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -365,14 +332,14 @@ void shouldReturnMsgWhenValidateMapSimple() { Employee validEmployee = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); - + Map employeeMap = new HashMap<>(); employeeMap.put("1", validEmployee); employeeMap.put("2", invalidEmployee1); employeeMap.put("3", invalidEmployee2); - - assertThatThrownBy(() -> validateService.validateEmployeeMap(employeeMap)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.validateEmployeeMap(employeeMap)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -380,21 +347,20 @@ void shouldReturnMsgWhenValidateMapSimple() { void shouldReturnMsgWhenValidateMapObj() { Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); - + ValidationTestData validData = new ValidationTestData(); validData.setName("Test"); validData.setAge(25); - + ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(""); invalidData.setAge(-1); - + Map map = new HashMap<>(); map.put(validEmployee, validData); map.put(invalidEmployee, invalidData); - - assertThatThrownBy(() -> validateService.validateEmployeeDataMap(map)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.validateEmployeeDataMap(map)).isInstanceOf(ConstraintViolationException.class); } @Test @@ -402,25 +368,25 @@ void shouldReturnMsgWhenValidateMapObj() { void shouldReturnMsgWhenValidateMapInMap() { Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); - + ValidationTestData validData = new ValidationTestData(); validData.setName("Test"); validData.setAge(25); - + ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(""); invalidData.setAge(-1); - + Map innerMap = new HashMap<>(); innerMap.put("valid", validData); innerMap.put("invalid", invalidData); - + Map> nestedMap = new HashMap<>(); nestedMap.put(validEmployee, innerMap); nestedMap.put(invalidEmployee, innerMap); - assertThatThrownBy(() -> validateService.validateNestedEmployeeDataMap(nestedMap)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateNestedEmployeeDataMap(nestedMap)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -429,19 +395,19 @@ void shouldReturnMsgWhenValidateMapInList() { Employee validEmployee = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); - + Map map1 = new HashMap<>(); map1.put("valid", validEmployee); map1.put("invalid1", invalidEmployee1); - + Map map2 = new HashMap<>(); map2.put("valid", validEmployee); map2.put("invalid2", invalidEmployee2); - + List> listOfMaps = Arrays.asList(map1, map2); - assertThatThrownBy(() -> validateService.validateEmployeeMapList(listOfMaps)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateEmployeeMapList(listOfMaps)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -449,24 +415,24 @@ void shouldReturnMsgWhenValidateMapInList() { void shouldReturnMsgWhenValidateListInMap() { Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); - + ValidationTestData validData = new ValidationTestData(); validData.setName("Test"); validData.setAge(25); - + ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(""); invalidData.setAge(-1); - + List dataList1 = Arrays.asList(validData, invalidData); List dataList2 = Arrays.asList(validData); - + Map> map = new HashMap<>(); map.put(validEmployee, dataList1); map.put(invalidEmployee, dataList2); - assertThatThrownBy(() -> validateService.validateEmployeeDataListMap(map)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateEmployeeDataListMap(map)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -475,9 +441,9 @@ void shouldReturnMsgWhenValidateListComplex() { Employee invalidEmployee = new Employee("", 17); Company invalidCompany = new Company(Arrays.asList(invalidEmployee)); List companies = Arrays.asList(invalidCompany); - - assertThatThrownBy(() -> validateService.validateCompanyList(companies)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.validateCompanyList(companies)).isInstanceOf( + ConstraintViolationException.class); } @Test @@ -545,7 +511,7 @@ void testValidComplexObject() { validData.setQuantity(10); validData.setDiscount(new BigDecimal("-5.0")); validData.setAgreed(true); - + validateService.testValidObject(validData); } @@ -556,39 +522,36 @@ void testMultipleValidationFailures() { invalidData.setName(""); // 违反@NotBlank invalidData.setAge(-1); // 违反@Min(0) invalidData.setQuantity(-10); // 违反@Positive - - assertThatThrownBy(() -> validateService.testValidObject(invalidData)) - .isInstanceOf(ConstraintViolationException.class); + + assertThatThrownBy(() -> validateService.testValidObject(invalidData)).isInstanceOf(ConstraintViolationException.class); } @Test @DisplayName("测试混合原始类型和对象校验") void testMixedPrimitiveAndObjectValidation() { Employee invalidEmployee = new Employee("", 17); - assertThatThrownBy(() -> validateService.validateMixed(-1, invalidEmployee)) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateMixed(-1, invalidEmployee)).isInstanceOf( + ConstraintViolationException.class); } @Test @DisplayName("测试空集合和null值混合") void testEmptyCollectionAndNullMixed() { - assertThatThrownBy(() -> validateService.validateMixedCollections(null, Collections.emptyList())) - .isInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(() -> validateService.validateMixedCollections(null, Collections.emptyList())).isInstanceOf( + ConstraintViolationException.class); } @Test @DisplayName("测试@Range注解-最小值验证") void testRangeMinValidation() { - assertThatThrownBy(() -> this.validateService.testRange(5)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testRange(5)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("需要在10和100之间"); } @Test @DisplayName("测试@Range注解-最大值验证") void testRangeMaxValidation() { - assertThatThrownBy(() -> this.validateService.testRange(150)) - .isInstanceOf(ConstraintViolationException.class) + assertThatThrownBy(() -> this.validateService.testRange(150)).isInstanceOf(ConstraintViolationException.class) .hasMessageContaining("需要在10和100之间"); } @@ -613,8 +576,7 @@ void testRangeValidValue() { @Test @DisplayName("测试@Range注解-BigDecimal类型") void testRangeBigDecimalValidation() { - assertThatThrownBy(() -> this.validateService.testRangeBigDecimal(new BigDecimal("5.5"))) - .isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要在10和100之间"); + assertThatThrownBy(() -> this.validateService.testRangeBigDecimal(new BigDecimal("5.5"))).isInstanceOf( + ConstraintViolationException.class).hasMessageContaining("需要在10和100之间"); } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java index 09d467b9c..59acd0022 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -6,11 +6,10 @@ package modelengine.fitframework.validation.data; - +import java.util.List; import javax.validation.Valid; import javax.validation.constraints.NotNull; -import java.util.List; /** * 公司实体类。 @@ -22,9 +21,9 @@ public class Company { @NotNull @Valid private List employees; - + public Company() {} - + public Company(List employees) { this.employees = employees; } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java index a22ffb88b..6d8995fbe 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -18,17 +18,17 @@ public class Employee { @NotBlank(message = "姓名不能为空") private String name; - + @Min(value = 18, message = "年龄必须大于等于18") private int age; - + public Employee() {} - + public Employee(String name, int age) { this.name = name; this.age = age; } - + public String getName() { return name; } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index 8f769d031..ffcaf785f 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -28,8 +28,10 @@ public class GroupValidateService { @Component @Validated(ValidationTestData.StudentGroup.class) public static class StudentValidateService { - public void validateStudentAge(@Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) - @Max(value = 20, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) int age) { + public void validateStudentAge( + @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) @Max( + value = 20, message = "范围要在7~20之内", + groups = ValidationTestData.StudentGroup.class) int age) { LOG.debug("Validating student age: {}", age); } } @@ -38,8 +40,10 @@ public void validateStudentAge(@Min(value = 7, message = "范围要在7~20之内 @Component @Validated(ValidationTestData.TeacherGroup.class) public static class TeacherValidateService { - public void validateTeacherAge(@Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) - @Max(value = 65, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) int age) { + public void validateTeacherAge( + @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) @Max( + value = 65, message = "范围要在22~65之内", + groups = ValidationTestData.TeacherGroup.class) int age) { LOG.debug("Validating teacher age: {}", age); } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index c62cc716d..d804f5957 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -10,17 +10,38 @@ import modelengine.fitframework.annotation.Fit; import modelengine.fitframework.log.Logger; import modelengine.fitframework.validation.Validated; -import org.hibernate.validator.constraints.Range; - +import org.hibernate.validator.constraints.Range; -import javax.validation.Valid; -import javax.validation.constraints.*; import java.math.BigDecimal; import java.time.LocalDate; import java.util.List; import java.util.Map; +import javax.validation.Valid; +import javax.validation.constraints.AssertFalse; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.DecimalMax; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Digits; +import javax.validation.constraints.Email; +import javax.validation.constraints.Future; +import javax.validation.constraints.FutureOrPresent; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.Negative; +import javax.validation.constraints.NegativeOrZero; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Null; +import javax.validation.constraints.Past; +import javax.validation.constraints.PastOrPresent; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Positive; +import javax.validation.constraints.PositiveOrZero; +import javax.validation.constraints.Size; + /** * 表示测试用校验服务。 * @@ -34,10 +55,10 @@ public class ValidateService { @Fit private GroupValidateService.StudentValidateService studentValidateService; - + @Fit private GroupValidateService.TeacherValidateService teacherValidateService; - + @Fit private GroupValidateService.AdvancedValidateService advancedValidateService; @@ -53,7 +74,7 @@ public void foo0(@Positive(message = "必须是正数") int num) { /** * 测试结构体类型。 * - * @param employee 表示输入的 {@code Employee}。 + * @param employee 表示输入的 {@link Employee}。 */ public void foo1(@Valid Employee employee) { LOG.debug("{}", employee); @@ -62,7 +83,7 @@ public void foo1(@Valid Employee employee) { /** * 测试嵌套类型。 * - * @param company 表示输入的 {@code Company}。 + * @param company 表示输入的 {@link Company}。 */ public void foo2(@Valid Company company) { LOG.debug("{}", company); @@ -232,7 +253,7 @@ public void testAssertFalse(@AssertFalse boolean value) {} /** * 测试 Valid 对象验证。 * - * @param data 表示输入的 {@code ValidationTestData}。 + * @param data 表示输入的 {@link ValidationTestData}。 */ public void testValidObject(@Valid ValidationTestData data) {} @@ -253,7 +274,7 @@ public void testRangeBigDecimal(@Range(min = 10, max = 100, message = "需要在 /** * 验证 Employee 对象。 * - * @param employee 表示输入的 {@code Employee}。 + * @param employee 表示输入的 {@link Employee}。 */ public void validateEmployee(@Valid Employee employee) { LOG.debug("Validating employee: {}", employee); @@ -281,7 +302,7 @@ public void validateNameAndAge(@NotBlank String name, @Positive int age) { /** * 验证高级分组数据。 * - * @param data 表示输入的 {@code ValidationTestData}。 + * @param data 表示输入的 {@link ValidationTestData}。 */ public void validateAdvancedGroup(ValidationTestData data) { if (advancedValidateService != null) { @@ -314,7 +335,7 @@ public void validateTeacherAge(int age) { /** * 验证公司对象。 * - * @param company 表示输入的 {@code Company}。 + * @param company 表示输入的 {@link Company}。 */ public void validateCompany(@Valid Company company) { LOG.debug("Validating company: {}", company); @@ -323,7 +344,7 @@ public void validateCompany(@Valid Company company) { /** * 验证员工列表。 * - * @param employees 表示输入的 {@code List}。 + * @param employees 表示输入的 {@link List}。 */ public void validateEmployeeList(List<@Valid Employee> employees) { LOG.debug("Validating employee list: {}", employees); @@ -332,7 +353,7 @@ public void validateEmployeeList(List<@Valid Employee> employees) { /** * 验证嵌套员工列表。 * - * @param nestedList 表示输入的 {@code List>}。 + * @param nestedList 表示输入的 {@link List>}。 */ public void validateNestedEmployeeList(List> nestedList) { LOG.debug("Validating nested employee list: {}", nestedList); @@ -341,7 +362,7 @@ public void validateNestedEmployeeList(List> nestedList) { /** * 验证员工映射。 * - * @param employeeMap 表示输入的 {@code Map}。 + * @param employeeMap 表示输入的 {@link Map}。 */ public void validateEmployeeMap(@Valid Map employeeMap) { LOG.debug("Validating employee map: {}", employeeMap); @@ -350,7 +371,7 @@ public void validateEmployeeMap(@Valid Map employeeMap) { /** * 验证员工数据映射。 * - * @param map 表示输入的 {@code Map}。 + * @param map 表示输入的 {@link Map}。 */ public void validateEmployeeDataMap(@Valid Map map) { LOG.debug("Validating employee data map: {}", map); @@ -359,7 +380,7 @@ public void validateEmployeeDataMap(@Valid Map map /** * 验证嵌套员工数据映射。 * - * @param nestedMap 表示输入的 {@code Map>}。 + * @param nestedMap 表示输入的 {@link Map>}。 */ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map> nestedMap) { LOG.debug("Validating nested employee data map: {}", nestedMap); @@ -368,7 +389,7 @@ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map>}。 + * @param listOfMaps 表示输入的 {@link List>}。 */ public void validateEmployeeMapList(List> listOfMaps) { LOG.debug("Validating employee map list: {}", listOfMaps); @@ -377,7 +398,7 @@ public void validateEmployeeMapList(List> listOfMap /** * 验证员工数据列表映射。 * - * @param map 表示输入的 {@code Map>}。 + * @param map 表示输入的 {@link Map>}。 */ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { LOG.debug("Validating employee data list map: {}", map); @@ -386,7 +407,7 @@ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid Validat /** * 验证公司列表。 * - * @param companies 表示输入的 {@code List}。 + * @param companies 表示输入的 {@link List}。 */ public void validateCompanyList(@Valid List companies) { LOG.debug("Validating company list: {}", companies); @@ -396,7 +417,7 @@ public void validateCompanyList(@Valid List companies) { * 验证混合类型数据。 * * @param value 表示输入的 {@code int}。 - * @param employee 表示输入的 {@code Employee}。 + * @param employee 表示输入的 {@link Employee}。 */ public void validateMixed(@Positive int value, @Valid Employee employee) { LOG.debug("Validating mixed primitive {} and object {}", value, employee); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index c6d37c10e..83c4b8f65 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -6,9 +6,14 @@ package modelengine.fitframework.validation.data; -import javax.validation.constraints.*; import java.math.BigDecimal; -import java.time.LocalDate; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.Negative; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Positive; /** * 测试用的复杂验证数据类。 @@ -20,52 +25,54 @@ public class ValidationTestData { // 分组接口定义 public interface AdvancedGroup {} + public interface StudentGroup {} + public interface TeacherGroup {} - + @NotBlank(message = "名称不能为空") private String name; - + @Min(value = 0, message = "年龄必须大于等于0") @Max(value = 150, message = "年龄必须小于等于150") @Max(value = 200, message = "高级组年龄必须小于等于200", groups = AdvancedGroup.class) private Integer age; - + @NotBlank(message = "描述不能为空") private String description; - + @NotBlank(message = "内容不能为空白") private String content; - + @Positive(message = "数量必须是正数") private Integer quantity; - + @Negative(message = "折扣必须是负数") private BigDecimal discount; - + @AssertTrue(message = "必须同意条款") private Boolean agreed; - + // 构造函数 public ValidationTestData() {} - + // Getters and Setters public String getName() { return name; } - + public void setName(String name) { this.name = name; } - + public void setAge(Integer age) { this.age = age; } - + public void setDescription(String description) { this.description = description; } - + public void setContent(String content) { this.content = content; } From 0ff67dc70a6cee67196bdfb825e8006a2d4656ca Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Thu, 14 Aug 2025 21:24:45 +0800 Subject: [PATCH 10/23] =?UTF-8?q?[fit]=20=E5=A4=84=E7=90=86=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=EF=BC=8C=E6=B3=A8=E9=87=8A=E5=92=8C=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...37\350\203\275\347\273\204\344\273\266.md" | 25 +++---------------- .../fit-validation-hibernate-jakarta/pom.xml | 4 +-- .../validation/ValidationHandler.java | 4 +-- .../fit-validation-hibernate-javax/pom.xml | 4 +-- .../validation/ValidationHandler.java | 4 +-- 5 files changed, 9 insertions(+), 32 deletions(-) diff --git "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" index ae013f758..7abecbfdd 100644 --- "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" +++ "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" @@ -219,29 +219,10 @@ FIT 框架提供了基于 Hibernate Validator 的数据校验功能,支持对 约束由约束注解和约束验证实现的组合定义。约束注解可以应用于类、方法、字段或其他约束注解(在组合的情况下)。 ## 12.3.1 依赖 -根据您的 Java 环境选择对应的插件: +当前FIT实现中同时存在两套 Validation 插件,分别对应 javax.validation 和 jakarta.validation 标准。 +两套校验插件同时运行,通过责任链的方式校验FIT程序中需要被校验的参数。 -**传统 Java EE 环境(javax):** - -```xml - - org.fitframework.plugin - fit-hibernate-validation - 3.6.0-SNAPSHOT - -``` - -**Jakarta EE 环境:** - -```xml - - org.fitframework.plugin - fit-hibernate-validation-jakarta - 3.6.0-SNAPSHOT - -``` - -同时根据您的 Java 环境选择对应的标准依赖: +用户可根据自己的开发需要,自行选择对应的标准依赖: **传统 Java EE 环境(javax):** diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml index d04352799..99e60117e 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml @@ -1,6 +1,6 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 @@ -20,8 +20,6 @@ 9.0.1.Final - - diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 37d38a5af..5a3ed5b00 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -56,8 +56,8 @@ public ValidationHandler() { /** * 方法参数校验处理。 * - * @param joinPoint 被拦截的连接点 {@link JoinPoint}。 - * @param validated 连接点上携带的校验注解 {@link Validated}。 + * @param joinPoint 表示切面的切点 {@link JoinPoint}。 + * @param validated 切点方法所属类的校验注解 {@link Validated}。 */ @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml index a23109c12..a9cf6b3d5 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml @@ -1,6 +1,6 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 @@ -20,8 +20,6 @@ 6.2.5.Final - - diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 09eafd88c..561dfba8c 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -57,8 +57,8 @@ public class ValidationHandler implements AutoCloseable { /** * 方法参数校验处理。 * - * @param joinPoint 被拦截的连接点 {@link JoinPoint}。 - * @param validated 连接点上携带的校验注解 {@link Validated}。 + * @param joinPoint 表示切面的切点 {@link JoinPoint}。 + * @param validated 切点方法所属类的校验注解 {@link Validated}。 */ @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { From 71c6f838c3d3e5a8ca3fba6947a6f4da00ad119b Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Sat, 16 Aug 2025 10:51:31 +0800 Subject: [PATCH 11/23] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E5=92=8C=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...345\212\237\350\203\275\347\273\204\344\273\266.md" | 10 +++++----- .../fitframework/validation/ValidationHandler.java | 5 ++++- .../fitframework/validation/ValidationHandler.java | 5 ++++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" index 7abecbfdd..fff04c5c2 100644 --- "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" +++ "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" @@ -219,8 +219,8 @@ FIT 框架提供了基于 Hibernate Validator 的数据校验功能,支持对 约束由约束注解和约束验证实现的组合定义。约束注解可以应用于类、方法、字段或其他约束注解(在组合的情况下)。 ## 12.3.1 依赖 -当前FIT实现中同时存在两套 Validation 插件,分别对应 javax.validation 和 jakarta.validation 标准。 -两套校验插件同时运行,通过责任链的方式校验FIT程序中需要被校验的参数。 +当前 FIT 实现中同时存在两套 Validation 插件,分别对应 javax.validation 和 jakarta.validation 标准。 +两套校验插件同时运行,通过责任链的方式校验 FIT 程序中需要被校验的参数。 用户可根据自己的开发需要,自行选择对应的标准依赖: @@ -256,7 +256,7 @@ FIT 框架提供了基于 Hibernate Validator 的数据校验功能,支持对 public class UserController { public void createUser(@NotBlank(message = "用户名不能为空") String username, - @Min(value = 18, message = "年龄必须大于等于18") Integer age) { + @Min(value = 18, message = "年龄必须大于等于 18") Integer age) { // 业务逻辑 } } @@ -269,8 +269,8 @@ public class UserDto { @NotBlank(message = "名称不能为空") private String name; - @Min(value = 0, message = "年龄必须大于等于0") - @Max(value = 150, message = "年龄必须小于等于150") + @Min(value = 0, message = "年龄必须大于等于 0") + @Max(value = 150, message = "年龄必须小于等于 150") private Integer age; @Email(message = "邮箱格式不正确") diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 5a3ed5b00..d330b2c98 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -124,6 +124,9 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { /** * 检查注解是否属于 jakarta.validation 注解。 + * 由于存在嵌套校验的情况, @Valid 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + * 1. @Valid 注解检查。如 void validateCompany(@Valid Company company)。 + * 2. 其他携带 Constraint 注解的校验注解检查。如 void validateEmployee(@NotBlank String name, @Positive int age)。 * * @param annotation 要检查的注解 {@link Annotation} * @return 如果属于 jakarta.validation 注解则返回 true,否则返回 false {@code boolean}。 @@ -133,7 +136,7 @@ private boolean isJakartaConstraintAnnotation(Annotation annotation) { if ("jakarta.validation.Valid".equals(annotation.annotationType().getName())) { return true; } - // jakarta.validation.constraints, org.hibernate.validator.constraints 包下的注解检查。 + // 检查 jakarta.validation.constraints, org.hibernate.validator.constraints 包下的注解或者用户根据 jakarta 标准自行实现的注解。 // 通过 Constraint 注解检查当前注解是否为校验注解。 Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); return Arrays.stream(metaAnnotations).anyMatch(metaAnnotation -> { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 561dfba8c..467499bea 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -125,6 +125,9 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { /** * 检查注解是否属于 javax.validation 注解。 + * 由于存在嵌套校验的情况, @Valid 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + * 1. @Valid 注解检查。如 void validateCompany(@Valid Company company)。 + * 2. 其他在 constraints 包下的注解检查。如 void validateEmployee(@NotBlank String name, @Positive int age)。 * * @param annotation 要检查的注解 {@link Annotation}。 * @return 如果属于 javax.validation 注解则返回 true,否则返回 false {@code boolean}。 @@ -134,7 +137,7 @@ private boolean isJavaxConstraintAnnotation(Annotation annotation) { if (annotation.annotationType().getName().equals("javax.validation.Valid")) { return true; } - // javax.validation.constraints, org.hibernate.validator.constraints 包下的注解检查。 + // 检查 javax.validation.constraints, org.hibernate.validator.constraints 包下的注解或者用户根据 javax 标准自行实现的注解检查。。 // 通过 Constraint 注解检查当前注解是否为校验注解。 Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); return Arrays.stream(metaAnnotations).anyMatch(metaAnnotation -> { From 7c0ed052e32556c345282b48181727c75c97e15c Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Sat, 16 Aug 2025 10:57:57 +0800 Subject: [PATCH 12/23] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...12\240\345\212\237\350\203\275\347\273\204\344\273\266.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" index fff04c5c2..27b0ccd07 100644 --- "a/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" +++ "b/docs/framework/fit/java/user-guide-book/12. \351\231\204\345\212\240\345\212\237\350\203\275\347\273\204\344\273\266.md" @@ -372,7 +372,7 @@ public void processComplexData(Map> companyGroup #### 空值校验 - `@NotNull`:值不能为 null -- `@NotEmpty`:值不能为 null 且不能为空(适用于字符串、集合、数组、Map) +- `@NotEmpty`:值不能为 null 且不能为空(适用于字符串、集合、数组、键值对) - `@NotBlank`:字符串不能为 null、空字符串或只包含空白字符 - `@Null`:值必须为 null @@ -395,7 +395,7 @@ public void processComplexData(Map> companyGroup #### 大小校验 -- `@Size(min, max)`:字符串、集合、数组、Map 的大小必须在指定范围内 +- `@Size(min, max)`:字符串、集合、数组、键值对的大小必须在指定范围内 #### 时间校验 From c2b65f06d37b4864d77e8d141da50674aa78dff9 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Sun, 17 Aug 2025 13:07:48 +0800 Subject: [PATCH 13/23] =?UTF-8?q?[fit]=20=E4=BF=AE=E6=94=B9=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=AE=9E=E7=8E=B0=EF=BC=8C=E5=BC=BA=E5=88=B6=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=9A=84=E8=AF=AD=E8=A8=80=EF=BC=8C=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fitframework/validation/Validated.java | 3 +- .../fit-validation-hibernate-jakarta/pom.xml | 2 +- .../validation/ValidationHandler.java | 27 +- .../validation/ValidationHandlerTest.java | 428 +++++++++++------ .../fitframework/validation/data/Company.java | 5 +- .../validation/data/Employee.java | 5 +- .../validation/data/ValidationTestData.java | 1 - .../fit-validation-hibernate-javax/pom.xml | 4 +- .../validation/ValidationHandler.java | 43 +- .../validation/ValidationHandlerTest.java | 431 ++++++++++++------ .../fitframework/validation/data/Company.java | 5 +- .../validation/data/Employee.java | 3 +- 12 files changed, 656 insertions(+), 301 deletions(-) diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java index 5cfe2f7e1..da5221360 100644 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java +++ b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2024 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -19,6 +19,7 @@ *

* * @author 邬涨财 + * @author 阮睿 * @since 2023-03-14 */ @Retention(RetentionPolicy.RUNTIME) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml index 99e60117e..41d45c5c1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml @@ -20,6 +20,7 @@ 9.0.1.Final + @@ -108,5 +109,4 @@
- diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index d330b2c98..24fe84259 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -81,10 +81,10 @@ public void close() { } /** - * 检查方法参数是否包含 jakarta.validation 校验注解。 + * 检查方法参数是否包含 {@code jakarta.validation} 校验注解。 * * @param parameters 方法参数数组 {@link Parameter[]}。 - * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 + * @return 如果包含 {@code jakarta.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { return Arrays.stream(parameters).anyMatch(this::hasConstraintAnnotationsInParameter); @@ -94,7 +94,7 @@ private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { * 检查参数及其泛型类型参数是否包含校验注解。 * * @param parameter 方法参数 {@link Parameter}。 - * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 + * @return 如果包含 {@code jakarta.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { return hasConstraintAnnotationsInType(parameter.getAnnotatedType()); @@ -104,7 +104,7 @@ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解。 * * @param annotatedType 参数注解类型 {@link AnnotatedType}。 - * @return 如果包含 jakarta.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 + * @return 如果包含 {@code jakarta.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { // 检查当前类型上的注解。 @@ -123,13 +123,20 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { } /** - * 检查注解是否属于 jakarta.validation 注解。 - * 由于存在嵌套校验的情况, @Valid 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: - * 1. @Valid 注解检查。如 void validateCompany(@Valid Company company)。 - * 2. 其他携带 Constraint 注解的校验注解检查。如 void validateEmployee(@NotBlank String name, @Positive int age)。 + *

+ * 检查注解是否属于 {@code jakarta.validation} 注解。 + * 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验, + * 但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + *

    + *
  1. {@code @Valid} 注解检查。用于标记需要级联校验的对象,例如: + * {@code void validateCompany(@Valid Company company)}。
  2. + *
  3. 其他携带 {@code @Constraint} 元注解的校验注解检查。例如: + * {@code void validateEmployee(@NotBlank String name, @Positive int age)}。
  4. + *
+ *

* - * @param annotation 要检查的注解 {@link Annotation} - * @return 如果属于 jakarta.validation 注解则返回 true,否则返回 false {@code boolean}。 + * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation} + * @return 如果属于 {@code jakarta.validation} 注解(即 @Valid 或携带 @Constraint),则返回 {@code true},否则返回 {@code false}。 */ private boolean isJakartaConstraintAnnotation(Annotation annotation) { // @Valid 注解检查。 diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index aafc8b33a..9fa28acd6 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -6,26 +6,40 @@ package modelengine.fitframework.validation; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowableOfType; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import jakarta.validation.ConstraintViolationException; -import modelengine.fitframework.annotation.Fit; -import modelengine.fitframework.test.annotation.FitTestWithJunit; +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.ioc.BeanContainer; +import modelengine.fitframework.ioc.annotation.AnnotationMetadataResolver; +import modelengine.fitframework.ioc.annotation.support.DefaultAnnotationMetadataResolver; +import modelengine.fitframework.runtime.FitRuntime; +import modelengine.fitframework.util.ObjectUtils; +import modelengine.fitframework.util.ReflectionUtils; import modelengine.fitframework.validation.data.Company; import modelengine.fitframework.validation.data.Employee; -import modelengine.fitframework.validation.data.GroupValidateService; -import modelengine.fitframework.validation.data.ValidateService; import modelengine.fitframework.validation.data.ValidationTestData; +import modelengine.fitframework.validation.data.ValidateService; +import modelengine.fitframework.validation.data.GroupValidateService; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.math.BigDecimal; import java.time.LocalDate; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; /** @@ -34,284 +48,416 @@ * @author 阮睿 * @since 2025-07-18 */ -@DisplayName("测试注解校验功能") -@FitTestWithJunit(includeClasses = { - ValidateService.class, ValidationHandler.class, GroupValidateService.StudentValidateService.class, - GroupValidateService.TeacherValidateService.class, GroupValidateService.AdvancedValidateService.class -}) public class ValidationHandlerTest { - @Fit - private ValidateService validateService; + static { + Locale.setDefault(Locale.CHINA); + } + + private final ValidateService validateService = mock(ValidateService.class); + private final BeanContainer beanContainer = mock(BeanContainer.class); + private final FitRuntime fitRuntime = mock(FitRuntime.class); + private final AnnotationMetadataResolver annotationMetadataResolver = new DefaultAnnotationMetadataResolver(); + private final Validated validated = Mockito.mock(Validated.class); + private final ValidationHandler handler = new ValidationHandler(); + + @BeforeEach + void setUp() { + when(validated.value()).thenReturn(new Class[0]); + when(fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); + when(beanContainer.runtime()).thenReturn(fitRuntime); + } + + private ConstraintViolationException invokeHandleMethod(Method targetMethod, Object[] args) { + Method handleValidatedMethod = + ReflectionUtils.getDeclaredMethod(ValidationHandler.class, "handle", JoinPoint.class, Validated.class); + handleValidatedMethod.setAccessible(true); + JoinPoint joinPoint = mock(JoinPoint.class); + when(joinPoint.getMethod()).thenReturn(targetMethod); + when(joinPoint.getArgs()).thenReturn(args); + when(joinPoint.getTarget()).thenReturn(validateService); + + InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, + () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + + return ObjectUtils.cast(invocationTargetException.getTargetException()); + } @Test @DisplayName("测试校验原始类型成功") void givePrimitiveThenValidateOk() { - assertThatThrownBy(() -> this.validateService.foo0(-1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是正数"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "foo0", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {-1}); + assertThat(exception.getMessage()).contains("必须是正数"); } @Test @DisplayName("测试校验结构体成功") void giveClassThenValidateOk() { - assertThatThrownBy(() -> this.validateService.foo1(new Employee("sky", 17))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("年龄必须大于等于18"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "foo1", Employee.class); + Employee employee = new Employee("sky", 17); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {employee}); + assertThat(exception.getMessage()).contains("年龄必须大于等于18"); } @Test @DisplayName("测试嵌套结构体成功") void giveNestedClassThenValidateOk() { - assertThatThrownBy(() -> { - Employee employee = new Employee("sky", 17); - this.validateService.foo2(new Company(Collections.singletonList(employee))); - }).isInstanceOf(ConstraintViolationException.class).hasMessageContaining("年龄必须大于等于18"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "foo2", Company.class); + Employee employee = new Employee("sky", 17); + Company company = new Company(Collections.singletonList(employee)); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {company}); + assertThat(exception.getMessage()).contains("年龄必须大于等于18"); } @Test @DisplayName("测试@NotNull注解") void testNotNullValidation() { - assertThatThrownBy(() -> this.validateService.testNotNull(null)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("不能为null"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNotNull", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {null}); + assertThat(exception.getMessage()).contains("不能为null"); } @Test @DisplayName("测试@NotEmpty注解") void testNotEmptyValidation() { - assertThatThrownBy(() -> this.validateService.testNotEmpty("")).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("不能为空"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNotEmpty", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {""}); + assertThat(exception.getMessage()).contains("不能为空"); } @Test @DisplayName("测试@NotBlank注解") void testNotBlankValidation() { - assertThatThrownBy(() -> this.validateService.testNotBlank(" ")).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("不能为空"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNotBlank", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {" "}); + assertThat(exception.getMessage()).contains("不能为空"); } @Test @DisplayName("测试@Null注解") void testNullValidation() { - assertThatThrownBy(() -> this.validateService.testNull("not null")).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须为null"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNull", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"not null"}); + assertThat(exception.getMessage()).contains("必须为null"); } @Test @DisplayName("测试@Size注解-字符串") void testSizeStringValidation() { - assertThatThrownBy(() -> this.validateService.testSize("a")).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("个数必须在2和10之间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testSize", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"a"}); + assertThat(exception.getMessage()).contains("个数必须在2和10之间"); } @Test @DisplayName("测试@Size注解-集合") void testSizeListValidation() { - assertThatThrownBy(() -> this.validateService.testSizeList(Arrays.asList("1", "2", "3", "4"))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("个数必须在1和3之间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testSizeList", List.class); + ConstraintViolationException exception = + invokeHandleMethod(method, new Object[] {Arrays.asList("1", "2", "3", "4")}); + assertThat(exception.getMessage()).contains("个数必须在1和3之间"); } @Test @DisplayName("测试@Min注解") void testMinValidation() { - assertThatThrownBy(() -> this.validateService.testMin(5)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("最小不能小于10"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testMin", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {5}); + assertThat(exception.getMessage()).contains("最小不能小于10"); } @Test @DisplayName("测试@Max注解") void testMaxValidation() { - assertThatThrownBy(() -> this.validateService.testMax(150)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("最大不能超过100"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testMax", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {150}); + assertThat(exception.getMessage()).contains("最大不能超过100"); } @Test @DisplayName("测试@DecimalMin注解") void testDecimalMinValidation() { - assertThatThrownBy(() -> this.validateService.testDecimalMin(new BigDecimal("5.0"))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("必须大于"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testDecimalMin", BigDecimal.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("5.0")}); + assertThat(exception.getMessage()).contains("必须大于"); } @Test @DisplayName("测试@DecimalMax注解") void testDecimalMaxValidation() { - assertThatThrownBy(() -> this.validateService.testDecimalMax(new BigDecimal("150.0"))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("必须小于"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testDecimalMax", BigDecimal.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("150.0")}); + assertThat(exception.getMessage()).contains("必须小于"); } @Test @DisplayName("测试@Positive注解") void testPositiveValidation() { - assertThatThrownBy(() -> this.validateService.testPositive(0)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是正数"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPositive", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {0}); + assertThat(exception.getMessage()).contains("必须是正数"); } @Test @DisplayName("测试@PositiveOrZero注解") void testPositiveOrZeroValidation() { - assertThatThrownBy(() -> this.validateService.testPositiveOrZero(-1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是正数或零"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPositiveOrZero", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {-1}); + assertThat(exception.getMessage()).contains("必须是正数或零"); } @Test @DisplayName("测试@Negative注解") void testNegativeValidation() { - assertThatThrownBy(() -> this.validateService.testNegative(1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是负数"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNegative", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {1}); + assertThat(exception.getMessage()).contains("必须是负数"); } @Test @DisplayName("测试@NegativeOrZero注解") void testNegativeOrZeroValidation() { - assertThatThrownBy(() -> this.validateService.testNegativeOrZero(1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是负数或零"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNegativeOrZero", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {1}); + assertThat(exception.getMessage()).contains("必须是负数或零"); } @Test @DisplayName("测试@Digits注解") void testDigitsValidation() { - assertThatThrownBy(() -> this.validateService.testDigits(new BigDecimal("1234.567"))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("数字的值超出了允许范围"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testDigits", BigDecimal.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("1234.567")}); + assertThat(exception.getMessage()).contains("数字的值超出了允许范围"); } @Test @DisplayName("测试@Past注解") void testPastValidation() { - assertThatThrownBy(() -> this.validateService.testPast(LocalDate.now().plusDays(1))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("需要是一个过去的时间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPast", LocalDate.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {LocalDate.now().plusDays(1)}); + assertThat(exception.getMessage()).contains("需要是一个过去的时间"); } @Test @DisplayName("测试@PastOrPresent注解") void testPastOrPresentValidation() { - assertThatThrownBy(() -> this.validateService.testPastOrPresent(LocalDate.now().plusDays(1))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("需要是一个过去或现在的时间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPastOrPresent", LocalDate.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {LocalDate.now().plusDays(1)}); + assertThat(exception.getMessage()).contains("需要是一个过去或现在的时间"); } @Test @DisplayName("测试@Future注解") void testFutureValidation() { - assertThatThrownBy(() -> this.validateService.testFuture(LocalDate.now().minusDays(1))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("需要是一个将来的时间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testFuture", LocalDate.class); + ConstraintViolationException exception = + invokeHandleMethod(method, new Object[] {LocalDate.now().minusDays(1)}); + assertThat(exception.getMessage()).contains("需要是一个将来的时间"); } @Test @DisplayName("测试@FutureOrPresent注解") void testFutureOrPresentValidation() { - assertThatThrownBy(() -> this.validateService.testFutureOrPresent(LocalDate.now().minusDays(1))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("需要是一个将来或现在的时间"); + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "testFutureOrPresent", LocalDate.class); + ConstraintViolationException exception = + invokeHandleMethod(method, new Object[] {LocalDate.now().minusDays(1)}); + assertThat(exception.getMessage()).contains("需要是一个将来或现在的时间"); } @Test @DisplayName("测试@Pattern注解") void testPatternValidation() { - assertThatThrownBy(() -> this.validateService.testPattern("123")).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要匹配正则表达式"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPattern", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"123"}); + assertThat(exception.getMessage()).contains("需要匹配正则表达式"); } @Test @DisplayName("测试@Email注解") void testEmailValidation() { - assertThatThrownBy(() -> this.validateService.testEmail("invalid-email")).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("不是一个合法的电子邮件地址"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testEmail", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"invalid-email"}); + assertThat(exception.getMessage()).contains("不是一个合法的电子邮件地址"); } @Test @DisplayName("测试@AssertTrue注解") void testAssertTrueValidation() { - assertThatThrownBy(() -> this.validateService.testAssertTrue(false)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("只能为true"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testAssertTrue", boolean.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {false}); + assertThat(exception.getMessage()).contains("只能为true"); } @Test @DisplayName("测试@AssertFalse注解") void testAssertFalseValidation() { - assertThatThrownBy(() -> this.validateService.testAssertFalse(true)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("只能为false"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testAssertFalse", boolean.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {true}); + assertThat(exception.getMessage()).contains("只能为false"); } @Test @DisplayName("测试复杂对象校验") void testComplexObjectValidation() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "testValidObject", ValidationTestData.class); ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(null); // 违反@NotNull invalidData.setAge(200); // 违反@Max(150) - assertThatThrownBy(() -> this.validateService.testValidObject(invalidData)).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("名称不能为空"); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {invalidData}); + assertThat(exception.getMessage()).contains("名称不能为空"); } @Test @DisplayName("校验数据类,该数据类的 Constraint 字段会被校验,其余字段不会被校验") public void givenFieldsWithConstraintAnnotationThenValidateHappened() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployee", Employee.class); Employee invalidEmployee = new Employee("", 150); // 空名字,年龄超限 - assertThatThrownBy(() -> validateService.validateEmployee(invalidEmployee)).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("不能为空"); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {invalidEmployee}); + assertThat(exception.getMessage()).contains("不能为空"); } @Test @DisplayName("校验方法参数,该方法的 Constraint 参数会被校验,其余参数不会被校验") public void givenParametersWithConstraintAnnotationThenValidateHappened() { - assertThatThrownBy(() -> validateService.validateAge(-1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是正数"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateAge", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {-1}); + assertThat(exception.getMessage()).contains("必须是正数"); } @Test @DisplayName("校验多个参数") public void givenMultipleParametersThenValidateHappened() { - assertThatThrownBy(() -> validateService.validateNameAndAge("", - -1)).isInstanceOf(ConstraintViolationException.class); - } - - @Test - @DisplayName("校验数据类,只会校验与数据类的分组一致的字段分组") - public void givenFieldsThenSameGroupValidateHappened() { - ValidationTestData data = new ValidationTestData(); - data.setAge(300); // 违反高级分组的约束 - data.setName(""); // 违反默认分组约束 - - assertThatThrownBy(() -> validateService.validateAdvancedGroup(data)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("高级组年龄必须小于等于200"); - } - - @Test - @DisplayName("校验方法参数,分组约束测试") - public void givenParametersThenGroupValidateHappened() { - // 测试学生年龄验证 - 现在会抛出异常,因为使用了学生分组 - assertThatThrownBy(() -> validateService.validateStudentAge(25)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("范围要在7~20之内"); - } - - @Test - @DisplayName("校验方法参数,教师年龄验证测试") - public void givenParametersThenTeacherGroupValidateNotHappened() { - // 测试教师年龄验证 - 现在会抛出异常,因为使用了教师分组 - assertThatThrownBy(() -> validateService.validateTeacherAge(15)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("范围要在22~65之内"); + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateNameAndAge", String.class, int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"", -1}); + assertThat(exception).isNotNull(); + } + + @Nested + @DisplayName("Student Group Validation Tests") + class StudentGroupValidationTests { + @Test + @DisplayName("校验方法参数,分组约束测试") + public void givenParametersThenGroupValidateHappened() { + // 测试学生年龄验证 - 现在会抛出异常,因为使用了学生分组 + Method method = ReflectionUtils.getDeclaredMethod(GroupValidateService.StudentValidateService.class, + "validateStudentAge", + int.class); + Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, + "handle", + JoinPoint.class, + Validated.class); + handleValidatedMethod.setAccessible(true); + JoinPoint joinPoint = mock(JoinPoint.class); + when(joinPoint.getMethod()).thenReturn(method); + when(joinPoint.getArgs()).thenReturn(new Object[] {25}); + when(joinPoint.getTarget()).thenReturn(new GroupValidateService.StudentValidateService()); + when(validated.value()).thenReturn(new Class[] {ValidationTestData.StudentGroup.class}); + + InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, + () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + + ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); + assertThat(exception.getMessage()).contains("范围要在7~20之内"); + } + } + + @Nested + @DisplayName("Teacher Group Validation Tests") + class TeacherGroupValidationTests { + @Test + @DisplayName("校验方法参数,教师年龄验证测试") + public void givenParametersThenTeacherGroupValidateNotHappened() { + // 测试教师年龄验证 - 现在会抛出异常,因为使用了教师分组 + Method method = ReflectionUtils.getDeclaredMethod(GroupValidateService.TeacherValidateService.class, + "validateTeacherAge", + int.class); + Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, + "handle", + JoinPoint.class, + Validated.class); + handleValidatedMethod.setAccessible(true); + JoinPoint joinPoint = mock(JoinPoint.class); + when(joinPoint.getMethod()).thenReturn(method); + when(joinPoint.getArgs()).thenReturn(new Object[] {15}); + when(joinPoint.getTarget()).thenReturn(new GroupValidateService.TeacherValidateService()); + when(validated.value()).thenReturn(new Class[] {ValidationTestData.TeacherGroup.class}); + + InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, + () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + + ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); + assertThat(exception.getMessage()).contains("范围要在22~65之内"); + } + } + + @Nested + @DisplayName("Advanced Group Validation Tests") + class AdvancedGroupValidationTests { + @Test + @DisplayName("测试验证高级分组数据") + void testValidateAdvancedGroup() { + // 测试高级分组验证 - 现在会抛出异常,因为使用了高级分组 + Method method = ReflectionUtils.getDeclaredMethod(GroupValidateService.AdvancedValidateService.class, + "validateAdvancedGroup", + ValidationTestData.class); + Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, + "handle", + JoinPoint.class, + Validated.class); + handleValidatedMethod.setAccessible(true); + JoinPoint joinPoint = mock(JoinPoint.class); + when(joinPoint.getMethod()).thenReturn(method); + + ValidationTestData data = new ValidationTestData(); + data.setAge(300); // 违反高级分组的约束 + data.setName(""); // 违反默认分组约束 + + when(joinPoint.getArgs()).thenReturn(new Object[] {data}); + when(joinPoint.getTarget()).thenReturn(new GroupValidateService.AdvancedValidateService()); + when(validated.value()).thenReturn(new Class[] {ValidationTestData.AdvancedGroup.class}); + + InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, + () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + + ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); + assertThat(exception.getMessage()).contains("高级组年龄必须小于等于200"); + } } @Test @DisplayName("测试嵌套校验类 Company") void shouldReturnMsgWhenValidateCompany() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateCompany", Company.class); Employee invalidEmployee1 = new Employee("", 17); // 空名字,年龄不足 Employee invalidEmployee2 = new Employee("John", 150); // 年龄超限 Company company = new Company(Arrays.asList(invalidEmployee1, invalidEmployee2)); - assertThatThrownBy(() -> validateService.validateCompany(company)).isInstanceOf(ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {company}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid List") void shouldReturnMsgWhenValidateList() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployeeList", List.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); List employees = Arrays.asList(validEmployee, invalidEmployee1, invalidEmployee2); - assertThatThrownBy(() -> validateService.validateEmployeeList(employees)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {employees}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid List>") void shouldReturnMsgWhenValidateListInList() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateNestedEmployeeList", List.class); Employee validEmployee1 = new Employee("John", 25); Employee validEmployee2 = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); @@ -321,13 +467,14 @@ void shouldReturnMsgWhenValidateListInList() { List employeeList2 = Arrays.asList(validEmployee2, invalidEmployee2); List> nestedList = Arrays.asList(employeeList1, employeeList2); - assertThatThrownBy(() -> validateService.validateNestedEmployeeList(nestedList)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {nestedList}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid Map") void shouldReturnMsgWhenValidateMapSimple() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployeeMap", Map.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); @@ -337,13 +484,14 @@ void shouldReturnMsgWhenValidateMapSimple() { employeeMap.put("2", invalidEmployee1); employeeMap.put("3", invalidEmployee2); - assertThatThrownBy(() -> validateService.validateEmployeeMap(employeeMap)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {employeeMap}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid Map") void shouldReturnMsgWhenValidateMapObj() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployeeDataMap", Map.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); @@ -359,12 +507,15 @@ void shouldReturnMsgWhenValidateMapObj() { map.put(validEmployee, validData); map.put(invalidEmployee, invalidData); - assertThatThrownBy(() -> validateService.validateEmployeeDataMap(map)).isInstanceOf(ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {map}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid Map>") void shouldReturnMsgWhenValidateMapInMap() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateNestedEmployeeDataMap", Map.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); @@ -384,13 +535,14 @@ void shouldReturnMsgWhenValidateMapInMap() { nestedMap.put(validEmployee, innerMap); nestedMap.put(invalidEmployee, innerMap); - assertThatThrownBy(() -> validateService.validateNestedEmployeeDataMap(nestedMap)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {nestedMap}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid List>") void shouldReturnMsgWhenValidateMapInList() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployeeMapList", List.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); @@ -405,13 +557,15 @@ void shouldReturnMsgWhenValidateMapInList() { List> listOfMaps = Arrays.asList(map1, map2); - assertThatThrownBy(() -> validateService.validateEmployeeMapList(listOfMaps)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {listOfMaps}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid Map>") void shouldReturnMsgWhenValidateListInMap() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployeeDataListMap", Map.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); @@ -430,19 +584,20 @@ void shouldReturnMsgWhenValidateListInMap() { map.put(validEmployee, dataList1); map.put(invalidEmployee, dataList2); - assertThatThrownBy(() -> validateService.validateEmployeeDataListMap(map)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {map}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid List") void shouldReturnMsgWhenValidateListComplex() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateCompanyList", List.class); Employee invalidEmployee = new Employee("", 17); Company invalidCompany = new Company(Arrays.asList(invalidEmployee)); List companies = Arrays.asList(invalidCompany); - assertThatThrownBy(() -> validateService.validateCompanyList(companies)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {companies}); + assertThat(exception).isNotNull(); } @Test @@ -517,41 +672,53 @@ void testValidComplexObject() { @Test @DisplayName("测试多个验证失败") void testMultipleValidationFailures() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "testValidObject", ValidationTestData.class); ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(""); // 违反@NotBlank invalidData.setAge(-1); // 违反@Min(0) invalidData.setQuantity(-10); // 违反@Positive - assertThatThrownBy(() -> validateService.testValidObject(invalidData)).isInstanceOf(ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {invalidData}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试混合原始类型和对象校验") void testMixedPrimitiveAndObjectValidation() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateMixed", int.class, Employee.class); Employee invalidEmployee = new Employee("", 17); - assertThatThrownBy(() -> validateService.validateMixed(-1, invalidEmployee)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {-1, invalidEmployee}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试空集合和null值混合") void testEmptyCollectionAndNullMixed() { - assertThatThrownBy(() -> validateService.validateMixedCollections(null, Collections.emptyList())).isInstanceOf( - ConstraintViolationException.class); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, + "validateMixedCollections", + List.class, + List.class); + ConstraintViolationException exception = + invokeHandleMethod(method, new Object[] {null, Collections.emptyList()}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试@Range注解-最小值验证") void testRangeMinValidation() { - assertThatThrownBy(() -> this.validateService.testRange(5)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要在10和100之间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRange", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {5}); + assertThat(exception.getMessage()).contains("需要在10和100之间"); } @Test @DisplayName("测试@Range注解-最大值验证") void testRangeMaxValidation() { - assertThatThrownBy(() -> this.validateService.testRange(150)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要在10和100之间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRange", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {150}); + assertThat(exception.getMessage()).contains("需要在10和100之间"); } @Test @@ -575,8 +742,9 @@ void testRangeValidValue() { @Test @DisplayName("测试@Range注解-BigDecimal类型") void testRangeBigDecimalValidation() { - assertThatThrownBy(() -> this.validateService.testRangeBigDecimal(new BigDecimal("5.5"))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("需要在10和100之间"); + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRangeBigDecimal", BigDecimal.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("5.5")}); + assertThat(exception.getMessage()).contains("需要在10和100之间"); } - -} \ No newline at end of file +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java index 17f9e2447..d80b6b783 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -14,8 +14,9 @@ /** * 公司实体类。 * + * @author 易文渊 * @author 阮睿 - * @since 2025-07-18 + * @since 2024-09-27 */ public class Company { @NotNull diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java index bb0fb1cfe..b4488e3c9 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -12,8 +12,9 @@ /** * 员工实体类。 * + * @author 易文渊 * @author 阮睿 - * @since 2025-07-18 + * @since 2024-09-27 */ public class Employee { @NotBlank(message = "姓名不能为空") diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index dbf40cfaf..8e8abaf3a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -22,7 +22,6 @@ * @since 2025-07-18 */ public class ValidationTestData { - // 分组接口定义 public interface AdvancedGroup {} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml index a9cf6b3d5..0d0e43be2 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml @@ -11,7 +11,7 @@ fit-validation-hibernate-javax - FIT Hibernate Validation + FIT Hibernate Validation Javax FIT Framework Hibernate Validation module provides Validation for args. https://github.com/ModelEngine-Group/fit-framework @@ -20,6 +20,7 @@ 6.2.5.Final + @@ -108,5 +109,4 @@ - diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 467499bea..1a673b370 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -6,6 +6,13 @@ package modelengine.fitframework.validation; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import javax.validation.executable.ExecutableValidator; + import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Scope; import modelengine.fitframework.aop.JoinPoint; @@ -23,13 +30,6 @@ import java.util.Arrays; import java.util.Set; -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; -import javax.validation.executable.ExecutableValidator; - /** * 校验入口类。 *

@@ -45,7 +45,7 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; - ValidationHandler() { + public ValidationHandler() { this.validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() .messageInterpolator(new ParameterMessageInterpolator()) @@ -82,10 +82,10 @@ public void close() { } /** - * 检查方法参数是否包含 javax.validation 校验注解。 + * 检查方法参数是否包含 {@code javax.validation} 校验注解。 * * @param parameters 方法参数数组 {@link Parameter[]}。 - * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 + * @return 如果包含 {@code javax.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { return Arrays.stream(parameters).anyMatch(this::hasConstraintAnnotationsInParameter); @@ -95,7 +95,7 @@ private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { * 检查参数及其泛型类型参数是否包含校验注解。 * * @param parameter 方法参数数组 {@link Parameter}。 - * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 + * @return 如果包含 {@code javax.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { return hasConstraintAnnotationsInType(parameter.getAnnotatedType()); @@ -105,7 +105,7 @@ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解。 * * @param annotatedType 参数注解类型 {@link AnnotatedType}。 - * @return 如果包含 javax.validation 标注的校验注解则返回 true,否则返回 false {@code boolean}。 + * @return 如果包含 {@code javax.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { // 检查当前类型上的注解。 @@ -124,13 +124,20 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { } /** - * 检查注解是否属于 javax.validation 注解。 - * 由于存在嵌套校验的情况, @Valid 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: - * 1. @Valid 注解检查。如 void validateCompany(@Valid Company company)。 - * 2. 其他在 constraints 包下的注解检查。如 void validateEmployee(@NotBlank String name, @Positive int age)。 + *

+ * 检查注解是否属于 {@code javax.validation} 注解。 + * 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验, + * 但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + *

    + *
  1. {@code @Valid} 注解检查。用于标记需要级联校验的对象,例如: + * {@code void validateCompany(@Valid Company company)}。
  2. + *
  3. 其他携带 {@code @Constraint} 元注解的校验注解检查。例如: + * {@code void validateEmployee(@NotBlank String name, @Positive int age)}。
  4. + *
+ *

* - * @param annotation 要检查的注解 {@link Annotation}。 - * @return 如果属于 javax.validation 注解则返回 true,否则返回 false {@code boolean}。 + * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation} + * @return 如果属于 {@code javax.validation} 注解(即 @Valid 或携带 @Constraint),则返回 {@code true},否则返回 {@code false}。 */ private boolean isJavaxConstraintAnnotation(Annotation annotation) { // @Valid 注解检查。 diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index fc07c3e88..f4fe5cb6a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -6,313 +6,459 @@ package modelengine.fitframework.validation; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowableOfType; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -import modelengine.fitframework.annotation.Fit; -import modelengine.fitframework.test.annotation.FitTestWithJunit; +import javax.validation.ConstraintViolationException; + +import modelengine.fitframework.aop.JoinPoint; +import modelengine.fitframework.ioc.BeanContainer; +import modelengine.fitframework.ioc.annotation.AnnotationMetadataResolver; +import modelengine.fitframework.ioc.annotation.support.DefaultAnnotationMetadataResolver; +import modelengine.fitframework.runtime.FitRuntime; +import modelengine.fitframework.util.ObjectUtils; +import modelengine.fitframework.util.ReflectionUtils; import modelengine.fitframework.validation.data.Company; import modelengine.fitframework.validation.data.Employee; -import modelengine.fitframework.validation.data.GroupValidateService; -import modelengine.fitframework.validation.data.ValidateService; import modelengine.fitframework.validation.data.ValidationTestData; +import modelengine.fitframework.validation.data.ValidateService; +import modelengine.fitframework.validation.data.GroupValidateService; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.math.BigDecimal; import java.time.LocalDate; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; -import javax.validation.ConstraintViolationException; - /** * {@link ValidationHandler} 的单元测试。 * * @author 阮睿 * @since 2025-07-18 */ -@DisplayName("测试注解校验功能") -@FitTestWithJunit(includeClasses = { - ValidateService.class, ValidationHandler.class, GroupValidateService.StudentValidateService.class, - GroupValidateService.TeacherValidateService.class, GroupValidateService.AdvancedValidateService.class -}) public class ValidationHandlerTest { - @Fit - private ValidateService validateService; + static { + Locale.setDefault(Locale.CHINA); + } + + private final ValidateService validateService = mock(ValidateService.class); + private final BeanContainer beanContainer = mock(BeanContainer.class); + private final FitRuntime fitRuntime = mock(FitRuntime.class); + private final AnnotationMetadataResolver annotationMetadataResolver = new DefaultAnnotationMetadataResolver(); + private final Validated validated = Mockito.mock(Validated.class); + private final ValidationHandler handler = new ValidationHandler(); + + @BeforeEach + void setUp() { + when(validated.value()).thenReturn(new Class[0]); + when(fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); + when(beanContainer.runtime()).thenReturn(fitRuntime); + } + + private ConstraintViolationException invokeHandleMethod(Method targetMethod, Object[] args) { + Method handleValidatedMethod = + ReflectionUtils.getDeclaredMethod(ValidationHandler.class, "handle", JoinPoint.class, Validated.class); + handleValidatedMethod.setAccessible(true); + JoinPoint joinPoint = mock(JoinPoint.class); + when(joinPoint.getMethod()).thenReturn(targetMethod); + when(joinPoint.getArgs()).thenReturn(args); + when(joinPoint.getTarget()).thenReturn(validateService); + + InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, + () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + + return ObjectUtils.cast(invocationTargetException.getTargetException()); + } @Test @DisplayName("测试校验原始类型成功") void givePrimitiveThenValidateOk() { - assertThatThrownBy(() -> this.validateService.foo0(-1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是正数"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "foo0", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {-1}); + assertThat(exception.getMessage()).contains("必须是正数"); } @Test @DisplayName("测试校验结构体成功") void giveClassThenValidateOk() { - assertThatThrownBy(() -> this.validateService.foo1(new Employee("sky", 17))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("年龄必须大于等于18"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "foo1", Employee.class); + Employee employee = new Employee("sky", 17); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {employee}); + assertThat(exception.getMessage()).contains("年龄必须大于等于18"); } @Test @DisplayName("测试嵌套结构体成功") void giveNestedClassThenValidateOk() { - assertThatThrownBy(() -> { - Employee employee = new Employee("sky", 17); - this.validateService.foo2(new Company(Collections.singletonList(employee))); - }).isInstanceOf(ConstraintViolationException.class).hasMessageContaining("年龄必须大于等于18"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "foo2", Company.class); + Employee employee = new Employee("sky", 17); + Company company = new Company(Collections.singletonList(employee)); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {company}); + assertThat(exception.getMessage()).contains("年龄必须大于等于18"); } @Test @DisplayName("测试@NotNull注解") void testNotNullValidation() { - assertThatThrownBy(() -> this.validateService.testNotNull(null)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("不能为null"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNotNull", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {null}); + assertThat(exception.getMessage()).contains("不能为null"); } @Test @DisplayName("测试@NotEmpty注解") void testNotEmptyValidation() { - assertThatThrownBy(() -> this.validateService.testNotEmpty("")).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("不能为空"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNotEmpty", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {""}); + assertThat(exception.getMessage()).contains("不能为空"); } @Test @DisplayName("测试@NotBlank注解") void testNotBlankValidation() { - assertThatThrownBy(() -> this.validateService.testNotBlank(" ")).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("不能为空"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNotBlank", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {" "}); + assertThat(exception.getMessage()).contains("不能为空"); } @Test @DisplayName("测试@Null注解") void testNullValidation() { - assertThatThrownBy(() -> this.validateService.testNull("not null")).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须为null"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNull", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"not null"}); + assertThat(exception.getMessage()).contains("必须为null"); } @Test @DisplayName("测试@Size注解-字符串") void testSizeStringValidation() { - assertThatThrownBy(() -> this.validateService.testSize("a")).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("个数必须在2和10之间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testSize", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"a"}); + assertThat(exception.getMessage()).contains("个数必须在2和10之间"); } @Test @DisplayName("测试@Size注解-集合") void testSizeListValidation() { - assertThatThrownBy(() -> this.validateService.testSizeList(Arrays.asList("1", "2", "3", "4"))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("个数必须在1和3之间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testSizeList", List.class); + ConstraintViolationException exception = + invokeHandleMethod(method, new Object[] {Arrays.asList("1", "2", "3", "4")}); + assertThat(exception.getMessage()).contains("个数必须在1和3之间"); } @Test @DisplayName("测试@Min注解") void testMinValidation() { - assertThatThrownBy(() -> this.validateService.testMin(5)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("最小不能小于10"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testMin", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {5}); + assertThat(exception.getMessage()).contains("最小不能小于10"); } @Test @DisplayName("测试@Max注解") void testMaxValidation() { - assertThatThrownBy(() -> this.validateService.testMax(150)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("最大不能超过100"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testMax", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {150}); + assertThat(exception.getMessage()).contains("最大不能超过100"); } @Test @DisplayName("测试@DecimalMin注解") void testDecimalMinValidation() { - assertThatThrownBy(() -> this.validateService.testDecimalMin(new BigDecimal("5.0"))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("必须大于"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testDecimalMin", BigDecimal.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("5.0")}); + assertThat(exception.getMessage()).contains("必须大于"); } @Test @DisplayName("测试@DecimalMax注解") void testDecimalMaxValidation() { - assertThatThrownBy(() -> this.validateService.testDecimalMax(new BigDecimal("150.0"))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("必须小于"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testDecimalMax", BigDecimal.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("150.0")}); + assertThat(exception.getMessage()).contains("必须小于"); } @Test @DisplayName("测试@Positive注解") void testPositiveValidation() { - assertThatThrownBy(() -> this.validateService.testPositive(0)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是正数"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPositive", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {0}); + assertThat(exception.getMessage()).contains("必须是正数"); } @Test @DisplayName("测试@PositiveOrZero注解") void testPositiveOrZeroValidation() { - assertThatThrownBy(() -> this.validateService.testPositiveOrZero(-1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是正数或零"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPositiveOrZero", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {-1}); + assertThat(exception.getMessage()).contains("必须是正数或零"); } @Test @DisplayName("测试@Negative注解") void testNegativeValidation() { - assertThatThrownBy(() -> this.validateService.testNegative(1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是负数"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNegative", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {1}); + assertThat(exception.getMessage()).contains("必须是负数"); } @Test @DisplayName("测试@NegativeOrZero注解") void testNegativeOrZeroValidation() { - assertThatThrownBy(() -> this.validateService.testNegativeOrZero(1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是负数或零"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNegativeOrZero", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {1}); + assertThat(exception.getMessage()).contains("必须是负数或零"); } @Test @DisplayName("测试@Digits注解") void testDigitsValidation() { - assertThatThrownBy(() -> this.validateService.testDigits(new BigDecimal("1234.567"))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("数字的值超出了允许范围"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testDigits", BigDecimal.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("1234.567")}); + assertThat(exception.getMessage()).contains("数字的值超出了允许范围"); } @Test @DisplayName("测试@Past注解") void testPastValidation() { - assertThatThrownBy(() -> this.validateService.testPast(LocalDate.now().plusDays(1))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("需要是一个过去的时间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPast", LocalDate.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {LocalDate.now().plusDays(1)}); + assertThat(exception.getMessage()).contains("需要是一个过去的时间"); } @Test @DisplayName("测试@PastOrPresent注解") void testPastOrPresentValidation() { - assertThatThrownBy(() -> this.validateService.testPastOrPresent(LocalDate.now().plusDays(1))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("需要是一个过去或现在的时间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPastOrPresent", LocalDate.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {LocalDate.now().plusDays(1)}); + assertThat(exception.getMessage()).contains("需要是一个过去或现在的时间"); } @Test @DisplayName("测试@Future注解") void testFutureValidation() { - assertThatThrownBy(() -> this.validateService.testFuture(LocalDate.now().minusDays(1))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("需要是一个将来的时间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testFuture", LocalDate.class); + ConstraintViolationException exception = + invokeHandleMethod(method, new Object[] {LocalDate.now().minusDays(1)}); + assertThat(exception.getMessage()).contains("需要是一个将来的时间"); } @Test @DisplayName("测试@FutureOrPresent注解") void testFutureOrPresentValidation() { - assertThatThrownBy(() -> this.validateService.testFutureOrPresent(LocalDate.now().minusDays(1))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("需要是一个将来或现在的时间"); + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "testFutureOrPresent", LocalDate.class); + ConstraintViolationException exception = + invokeHandleMethod(method, new Object[] {LocalDate.now().minusDays(1)}); + assertThat(exception.getMessage()).contains("需要是一个将来或现在的时间"); } @Test @DisplayName("测试@Pattern注解") void testPatternValidation() { - assertThatThrownBy(() -> this.validateService.testPattern("123")).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要匹配正则表达式"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPattern", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"123"}); + assertThat(exception.getMessage()).contains("需要匹配正则表达式"); } @Test @DisplayName("测试@Email注解") void testEmailValidation() { - assertThatThrownBy(() -> this.validateService.testEmail("invalid-email")).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("不是一个合法的电子邮件地址"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testEmail", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"invalid-email"}); + assertThat(exception.getMessage()).contains("不是一个合法的电子邮件地址"); } @Test @DisplayName("测试@AssertTrue注解") void testAssertTrueValidation() { - assertThatThrownBy(() -> this.validateService.testAssertTrue(false)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("只能为true"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testAssertTrue", boolean.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {false}); + assertThat(exception.getMessage()).contains("只能为true"); } @Test @DisplayName("测试@AssertFalse注解") void testAssertFalseValidation() { - assertThatThrownBy(() -> this.validateService.testAssertFalse(true)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("只能为false"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testAssertFalse", boolean.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {true}); + assertThat(exception.getMessage()).contains("只能为false"); } @Test @DisplayName("测试复杂对象校验") void testComplexObjectValidation() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "testValidObject", ValidationTestData.class); ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(null); // 违反@NotNull invalidData.setAge(200); // 违反@Max(150) - assertThatThrownBy(() -> this.validateService.testValidObject(invalidData)).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("名称不能为空"); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {invalidData}); + assertThat(exception.getMessage()).contains("名称不能为空"); } @Test @DisplayName("校验数据类,该数据类的 Constraint 字段会被校验,其余字段不会被校验") public void givenFieldsWithConstraintAnnotationThenValidateHappened() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployee", Employee.class); Employee invalidEmployee = new Employee("", 150); // 空名字,年龄超限 - assertThatThrownBy(() -> validateService.validateEmployee(invalidEmployee)).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("不能为空"); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {invalidEmployee}); + assertThat(exception.getMessage()).contains("不能为空"); } @Test @DisplayName("校验方法参数,该方法的 Constraint 参数会被校验,其余参数不会被校验") public void givenParametersWithConstraintAnnotationThenValidateHappened() { - assertThatThrownBy(() -> validateService.validateAge(-1)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("必须是正数"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateAge", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {-1}); + assertThat(exception.getMessage()).contains("必须是正数"); } @Test @DisplayName("校验多个参数") public void givenMultipleParametersThenValidateHappened() { - assertThatThrownBy(() -> validateService.validateNameAndAge("", - -1)).isInstanceOf(ConstraintViolationException.class); - } - - @Test - @DisplayName("校验数据类,只会校验与数据类的分组一致的字段分组") - public void givenFieldsThenSameGroupValidateHappened() { - ValidationTestData data = new ValidationTestData(); - data.setAge(300); // 违反高级分组的约束 - data.setName(""); // 违反默认分组约束 - - assertThatThrownBy(() -> validateService.validateAdvancedGroup(data)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("高级组年龄必须小于等于200"); - } - - @Test - @DisplayName("校验方法参数,分组约束测试") - public void givenParametersThenGroupValidateHappened() { - // 测试学生年龄验证 - 现在会抛出异常,因为使用了学生分组 - assertThatThrownBy(() -> validateService.validateStudentAge(25)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("范围要在7~20之内"); - } - - @Test - @DisplayName("校验方法参数,教师年龄验证测试") - public void givenParametersThenTeacherGroupValidateNotHappened() { - // 测试教师年龄验证 - 现在会抛出异常,因为使用了教师分组 - assertThatThrownBy(() -> validateService.validateTeacherAge(15)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("范围要在22~65之内"); + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateNameAndAge", String.class, int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"", -1}); + assertThat(exception).isNotNull(); + } + + @Nested + @DisplayName("Student Group Validation Tests") + class StudentGroupValidationTests { + @Test + @DisplayName("校验方法参数,分组约束测试") + public void givenParametersThenGroupValidateHappened() { + // 测试学生年龄验证 - 现在会抛出异常,因为使用了学生分组 + Method method = ReflectionUtils.getDeclaredMethod(GroupValidateService.StudentValidateService.class, + "validateStudentAge", + int.class); + Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, + "handle", + JoinPoint.class, + Validated.class); + handleValidatedMethod.setAccessible(true); + JoinPoint joinPoint = mock(JoinPoint.class); + when(joinPoint.getMethod()).thenReturn(method); + when(joinPoint.getArgs()).thenReturn(new Object[] {25}); + when(joinPoint.getTarget()).thenReturn(new GroupValidateService.StudentValidateService()); + when(validated.value()).thenReturn(new Class[] {ValidationTestData.StudentGroup.class}); + + InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, + () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + + ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); + assertThat(exception.getMessage()).contains("范围要在7~20之内"); + } + } + + @Nested + @DisplayName("Teacher Group Validation Tests") + class TeacherGroupValidationTests { + @Test + @DisplayName("校验方法参数,教师年龄验证测试") + public void givenParametersThenTeacherGroupValidateNotHappened() { + // 测试教师年龄验证 - 现在会抛出异常,因为使用了教师分组 + Method method = ReflectionUtils.getDeclaredMethod(GroupValidateService.TeacherValidateService.class, + "validateTeacherAge", + int.class); + Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, + "handle", + JoinPoint.class, + Validated.class); + handleValidatedMethod.setAccessible(true); + JoinPoint joinPoint = mock(JoinPoint.class); + when(joinPoint.getMethod()).thenReturn(method); + when(joinPoint.getArgs()).thenReturn(new Object[] {15}); + when(joinPoint.getTarget()).thenReturn(new GroupValidateService.TeacherValidateService()); + when(validated.value()).thenReturn(new Class[] {ValidationTestData.TeacherGroup.class}); + + InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, + () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + + ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); + assertThat(exception.getMessage()).contains("范围要在22~65之内"); + } + } + + @Nested + @DisplayName("Advanced Group Validation Tests") + class AdvancedGroupValidationTests { + @Test + @DisplayName("测试验证高级分组数据") + void testValidateAdvancedGroup() { + // 测试高级分组验证 - 现在会抛出异常,因为使用了高级分组 + Method method = ReflectionUtils.getDeclaredMethod(GroupValidateService.AdvancedValidateService.class, + "validateAdvancedGroup", + ValidationTestData.class); + Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, + "handle", + JoinPoint.class, + Validated.class); + handleValidatedMethod.setAccessible(true); + JoinPoint joinPoint = mock(JoinPoint.class); + when(joinPoint.getMethod()).thenReturn(method); + + ValidationTestData data = new ValidationTestData(); + data.setAge(300); // 违反高级分组的约束 + data.setName(""); // 违反默认分组约束 + + when(joinPoint.getArgs()).thenReturn(new Object[] {data}); + when(joinPoint.getTarget()).thenReturn(new GroupValidateService.AdvancedValidateService()); + when(validated.value()).thenReturn(new Class[] {ValidationTestData.AdvancedGroup.class}); + + InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, + () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + + ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); + assertThat(exception.getMessage()).contains("高级组年龄必须小于等于200"); + } } @Test @DisplayName("测试嵌套校验类 Company") void shouldReturnMsgWhenValidateCompany() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateCompany", Company.class); Employee invalidEmployee1 = new Employee("", 17); // 空名字,年龄不足 Employee invalidEmployee2 = new Employee("John", 150); // 年龄超限 Company company = new Company(Arrays.asList(invalidEmployee1, invalidEmployee2)); - assertThatThrownBy(() -> validateService.validateCompany(company)).isInstanceOf(ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {company}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid List") void shouldReturnMsgWhenValidateList() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployeeList", List.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); List employees = Arrays.asList(validEmployee, invalidEmployee1, invalidEmployee2); - assertThatThrownBy(() -> validateService.validateEmployeeList(employees)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {employees}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid List>") void shouldReturnMsgWhenValidateListInList() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateNestedEmployeeList", List.class); Employee validEmployee1 = new Employee("John", 25); Employee validEmployee2 = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); @@ -322,13 +468,14 @@ void shouldReturnMsgWhenValidateListInList() { List employeeList2 = Arrays.asList(validEmployee2, invalidEmployee2); List> nestedList = Arrays.asList(employeeList1, employeeList2); - assertThatThrownBy(() -> validateService.validateNestedEmployeeList(nestedList)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {nestedList}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid Map") void shouldReturnMsgWhenValidateMapSimple() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployeeMap", Map.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); @@ -338,13 +485,14 @@ void shouldReturnMsgWhenValidateMapSimple() { employeeMap.put("2", invalidEmployee1); employeeMap.put("3", invalidEmployee2); - assertThatThrownBy(() -> validateService.validateEmployeeMap(employeeMap)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {employeeMap}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid Map") void shouldReturnMsgWhenValidateMapObj() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployeeDataMap", Map.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); @@ -360,12 +508,15 @@ void shouldReturnMsgWhenValidateMapObj() { map.put(validEmployee, validData); map.put(invalidEmployee, invalidData); - assertThatThrownBy(() -> validateService.validateEmployeeDataMap(map)).isInstanceOf(ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {map}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid Map>") void shouldReturnMsgWhenValidateMapInMap() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateNestedEmployeeDataMap", Map.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); @@ -385,13 +536,14 @@ void shouldReturnMsgWhenValidateMapInMap() { nestedMap.put(validEmployee, innerMap); nestedMap.put(invalidEmployee, innerMap); - assertThatThrownBy(() -> validateService.validateNestedEmployeeDataMap(nestedMap)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {nestedMap}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid List>") void shouldReturnMsgWhenValidateMapInList() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployeeMapList", List.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee1 = new Employee("", 17); Employee invalidEmployee2 = new Employee("Jane", 150); @@ -406,13 +558,15 @@ void shouldReturnMsgWhenValidateMapInList() { List> listOfMaps = Arrays.asList(map1, map2); - assertThatThrownBy(() -> validateService.validateEmployeeMapList(listOfMaps)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {listOfMaps}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid Map>") void shouldReturnMsgWhenValidateListInMap() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateEmployeeDataListMap", Map.class); Employee validEmployee = new Employee("John", 25); Employee invalidEmployee = new Employee("", 17); @@ -431,19 +585,20 @@ void shouldReturnMsgWhenValidateListInMap() { map.put(validEmployee, dataList1); map.put(invalidEmployee, dataList2); - assertThatThrownBy(() -> validateService.validateEmployeeDataListMap(map)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {map}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试 @Valid List") void shouldReturnMsgWhenValidateListComplex() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateCompanyList", List.class); Employee invalidEmployee = new Employee("", 17); Company invalidCompany = new Company(Arrays.asList(invalidEmployee)); List companies = Arrays.asList(invalidCompany); - assertThatThrownBy(() -> validateService.validateCompanyList(companies)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {companies}); + assertThat(exception).isNotNull(); } @Test @@ -518,41 +673,53 @@ void testValidComplexObject() { @Test @DisplayName("测试多个验证失败") void testMultipleValidationFailures() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "testValidObject", ValidationTestData.class); ValidationTestData invalidData = new ValidationTestData(); invalidData.setName(""); // 违反@NotBlank invalidData.setAge(-1); // 违反@Min(0) invalidData.setQuantity(-10); // 违反@Positive - assertThatThrownBy(() -> validateService.testValidObject(invalidData)).isInstanceOf(ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {invalidData}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试混合原始类型和对象校验") void testMixedPrimitiveAndObjectValidation() { + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateMixed", int.class, Employee.class); Employee invalidEmployee = new Employee("", 17); - assertThatThrownBy(() -> validateService.validateMixed(-1, invalidEmployee)).isInstanceOf( - ConstraintViolationException.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {-1, invalidEmployee}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试空集合和null值混合") void testEmptyCollectionAndNullMixed() { - assertThatThrownBy(() -> validateService.validateMixedCollections(null, Collections.emptyList())).isInstanceOf( - ConstraintViolationException.class); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, + "validateMixedCollections", + List.class, + List.class); + ConstraintViolationException exception = + invokeHandleMethod(method, new Object[] {null, Collections.emptyList()}); + assertThat(exception).isNotNull(); } @Test @DisplayName("测试@Range注解-最小值验证") void testRangeMinValidation() { - assertThatThrownBy(() -> this.validateService.testRange(5)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要在10和100之间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRange", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {5}); + assertThat(exception.getMessage()).contains("需要在10和100之间"); } @Test @DisplayName("测试@Range注解-最大值验证") void testRangeMaxValidation() { - assertThatThrownBy(() -> this.validateService.testRange(150)).isInstanceOf(ConstraintViolationException.class) - .hasMessageContaining("需要在10和100之间"); + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRange", int.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {150}); + assertThat(exception.getMessage()).contains("需要在10和100之间"); } @Test @@ -576,7 +743,9 @@ void testRangeValidValue() { @Test @DisplayName("测试@Range注解-BigDecimal类型") void testRangeBigDecimalValidation() { - assertThatThrownBy(() -> this.validateService.testRangeBigDecimal(new BigDecimal("5.5"))).isInstanceOf( - ConstraintViolationException.class).hasMessageContaining("需要在10和100之间"); + Method method = + ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRangeBigDecimal", BigDecimal.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("5.5")}); + assertThat(exception.getMessage()).contains("需要在10和100之间"); } -} \ No newline at end of file +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java index 59acd0022..a7b74e335 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ @@ -14,8 +14,9 @@ /** * 公司实体类。 * + * @author 易文渊 * @author 阮睿 - * @since 2025-07-18 + * @since 2024-09-27 */ public class Company { @NotNull diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java index 6d8995fbe..f5dce43dd 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -12,8 +12,9 @@ /** * 员工实体类。 * + * @author 易文渊 * @author 阮睿 - * @since 2025-07-18 + * @since 2024-09-27 */ public class Employee { @NotBlank(message = "姓名不能为空") From 5afc650f0479a89d22cc68415b8cfcc68e73942a Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Sun, 17 Aug 2025 13:17:32 +0800 Subject: [PATCH 14/23] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fitframework/validation/data/ValidationTestData.java | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index 83c4b8f65..9a8180205 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -22,7 +22,6 @@ * @since 2025-07-18 */ public class ValidationTestData { - // 分组接口定义 public interface AdvancedGroup {} From a2e5e4d137d47e864a5de563f67a0c70ae43e03a Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Mon, 18 Aug 2025 10:20:44 +0800 Subject: [PATCH 15/23] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fitframework/validation/Validated.java | 4 +- .../validation/ValidationHandler.java | 14 +++--- .../validation/data/GroupValidateService.java | 6 +-- .../validation/data/ValidateService.java | 44 +++++++++---------- .../validation/data/ValidationTestData.java | 2 - .../validation/ValidationHandler.java | 15 +++---- .../validation/data/GroupValidateService.java | 6 +-- .../validation/data/ValidateService.java | 44 +++++++++---------- .../validation/data/ValidationTestData.java | 2 - 9 files changed, 64 insertions(+), 73 deletions(-) diff --git a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java index da5221360..7f9c22612 100644 --- a/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java +++ b/framework/fit/java/fit-api/src/main/java/modelengine/fitframework/validation/Validated.java @@ -14,8 +14,8 @@ /** * 表示校验的注解。 - *

用来标识所要校验的类,该类的所有公共方法中,所有被 javax 或 jakarta 校验注解 - * 标注的参数都会被校验 + *

+ * 用来标识所要校验的类,该类的所有公共方法中,所有被 javax 或 jakarta 校验注解标注的参数都会被校验。 *

* * @author 邬涨财 diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 24fe84259..04b397052 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -83,7 +83,7 @@ public void close() { /** * 检查方法参数是否包含 {@code jakarta.validation} 校验注解。 * - * @param parameters 方法参数数组 {@link Parameter[]}。 + * @param parameters 方法参数数组 {@link Parameter}{@code []}。 * @return 如果包含 {@code jakarta.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { @@ -125,15 +125,13 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { /** *

* 检查注解是否属于 {@code jakarta.validation} 注解。 - * 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验, - * 但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + *

+ * 由于存在嵌套校验的情况, {@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: *

    - *
  1. {@code @Valid} 注解检查。用于标记需要级联校验的对象,例如: - * {@code void validateCompany(@Valid Company company)}。
  2. - *
  3. 其他携带 {@code @Constraint} 元注解的校验注解检查。例如: - * {@code void validateEmployee(@NotBlank String name, @Positive int age)}。
  4. + *
  5. {@code @Valid} 注解检查。用于标记需要级联校验的对象,例如: {@code void validateCompany(@Valid Company company)}。
  6. + *
  7. 其他携带 {@code @Constraint} 元注解的校验注解检查。例如: {@code void validateEmployee(@NotBlank String name, @Positive int + * age)}。
  8. *
- *

* * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation} * @return 如果属于 {@code jakarta.validation} 注解(即 @Valid 或携带 @Constraint),则返回 {@code true},否则返回 {@code false}。 diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index 06f97c6a7..ffa8c0674 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -23,7 +23,7 @@ public class GroupValidateService { private static final Logger LOG = Logger.get(GroupValidateService.class); - // 学生年龄验证服务 + // 学生年龄验证服务。 @Component @Validated(ValidationTestData.StudentGroup.class) public static class StudentValidateService { @@ -35,7 +35,7 @@ public void validateStudentAge( } } - // 教师年龄验证服务 + // 教师年龄验证服务。 @Component @Validated(ValidationTestData.TeacherGroup.class) public static class TeacherValidateService { @@ -47,7 +47,7 @@ public void validateTeacherAge( } } - // 高级分组验证服务 + // 高级分组验证服务。 @Component @Validated(ValidationTestData.AdvancedGroup.class) public static class AdvancedValidateService { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index de4171580..0b2745cf0 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -91,35 +91,35 @@ public void foo2(@Valid Company company) { /** * 测试 NotNull 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testNotNull(@NotNull String value) {} /** * 测试 NotEmpty 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testNotEmpty(@NotEmpty String value) {} /** * 测试 NotBlank 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testNotBlank(@NotBlank String value) {} /** * 测试 Null 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testNull(@Null String value) {} /** * 测试 Size 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testSize(@Size(min = 2, max = 10) String value) {} @@ -147,14 +147,14 @@ public void testMax(@Max(100) int value) {} /** * 测试 DecimalMin 约束注解。 * - * @param value 表示输入的 {@code BigDecimal}。 + * @param value 表示输入的 {@link BigDecimal}。 */ public void testDecimalMin(@DecimalMin("10.5") BigDecimal value) {} /** * 测试 DecimalMax 约束注解。 * - * @param value 表示输入的 {@code BigDecimal}。 + * @param value 表示输入的 {@link BigDecimal}。 */ public void testDecimalMax(@DecimalMax("100.5") BigDecimal value) {} @@ -189,49 +189,49 @@ public void testNegativeOrZero(@NegativeOrZero int value) {} /** * 测试 Digits 约束注解。 * - * @param value 表示输入的 {@code BigDecimal}。 + * @param value 表示输入的 {@link BigDecimal}。 */ public void testDigits(@Digits(integer = 3, fraction = 2) BigDecimal value) {} /** * 测试 Past 约束注解。 * - * @param value 表示输入的 {@code LocalDate}。 + * @param value 表示输入的 {@link LocalDate}。 */ public void testPast(@Past LocalDate value) {} /** * 测试 PastOrPresent 约束注解。 * - * @param value 表示输入的 {@code LocalDate}。 + * @param value 表示输入的 {@link LocalDate}。 */ public void testPastOrPresent(@PastOrPresent LocalDate value) {} /** * 测试 Future 约束注解。 * - * @param value 表示输入的 {@code LocalDate}。 + * @param value 表示输入的 {@link LocalDate}。 */ public void testFuture(@Future LocalDate value) {} /** * 测试 FutureOrPresent 约束注解。 * - * @param value 表示输入的 {@code LocalDate}。 + * @param value 表示输入的 {@link LocalDate}。 */ public void testFutureOrPresent(@FutureOrPresent LocalDate value) {} /** * 测试 Pattern 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testPattern(@Pattern(regexp = "^[a-zA-Z]+$") String value) {} /** * 测试 Email 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testEmail(@Email String value) {} @@ -266,7 +266,7 @@ public void testRange(@Range(min = 10, max = 100, message = "需要在10和100 /** * 测试 BigDecimal 类型的Range约束注解。 * - * @param value 表示输入的 {@code BigDecimal}。 + * @param value 表示输入的 {@link BigDecimal}。 */ public void testRangeBigDecimal(@Range(min = 10, max = 100, message = "需要在10和100之间") BigDecimal value) {} @@ -291,7 +291,7 @@ public void validateAge(@Positive(message = "必须是正数") int age) { /** * 验证姓名和年龄。 * - * @param name 表示输入的 {@code String}。 + * @param name 表示输入的 {@link String}。 * @param age 表示输入的 {@code int}。 */ public void validateNameAndAge(@NotBlank String name, @Positive int age) { @@ -361,7 +361,7 @@ public void validateNestedEmployeeList(List> nestedList) { /** * 验证员工映射。 * - * @param employeeMap 表示输入的 {@link Map}。 + * @param employeeMap 表示输入的 {@code Map}。 */ public void validateEmployeeMap(@Valid Map employeeMap) { LOG.debug("Validating employee map: {}", employeeMap); @@ -370,7 +370,7 @@ public void validateEmployeeMap(@Valid Map employeeMap) { /** * 验证员工数据映射。 * - * @param map 表示输入的 {@link Map}。 + * @param map 表示输入的 {@code Map}。 */ public void validateEmployeeDataMap(@Valid Map map) { LOG.debug("Validating employee data map: {}", map); @@ -379,7 +379,7 @@ public void validateEmployeeDataMap(@Valid Map map /** * 验证嵌套员工数据映射。 * - * @param nestedMap 表示输入的 {@link Map>}。 + * @param nestedMap 表示输入的 {@code Map>}。 */ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map> nestedMap) { LOG.debug("Validating nested employee data map: {}", nestedMap); @@ -388,7 +388,7 @@ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map>}。 + * @param listOfMaps 表示输入的 {@code List>}。 */ public void validateEmployeeMapList(List> listOfMaps) { LOG.debug("Validating employee map list: {}", listOfMaps); @@ -397,7 +397,7 @@ public void validateEmployeeMapList(List> listOfMap /** * 验证员工数据列表映射。 * - * @param map 表示输入的 {@link Map>}。 + * @param map 表示输入的 {@code Map>}。 */ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { LOG.debug("Validating employee data list map: {}", map); @@ -406,7 +406,7 @@ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid Validat /** * 验证公司列表。 * - * @param companies 表示输入的 {@link List}。 + * @param companies 表示输入的 {@code List}。 */ public void validateCompanyList(@Valid List companies) { LOG.debug("Validating company list: {}", companies); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index 8e8abaf3a..b0af3c0e4 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -52,10 +52,8 @@ public interface TeacherGroup {} @AssertTrue(message = "必须同意条款") private Boolean agreed; - // 构造函数 public ValidationTestData() {} - // Getters and Setters public String getName() { return name; } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 1a673b370..deae481aa 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -12,7 +12,6 @@ import javax.validation.Validator; import javax.validation.ValidatorFactory; import javax.validation.executable.ExecutableValidator; - import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Scope; import modelengine.fitframework.aop.JoinPoint; @@ -84,7 +83,7 @@ public void close() { /** * 检查方法参数是否包含 {@code javax.validation} 校验注解。 * - * @param parameters 方法参数数组 {@link Parameter[]}。 + * @param parameters 方法参数数组 {@link Parameter}{@code []}。 * @return 如果包含 {@code javax.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { @@ -126,15 +125,13 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { /** *

* 检查注解是否属于 {@code javax.validation} 注解。 - * 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验, - * 但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + *

+ * 由于存在嵌套校验的情况, {@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: *

    - *
  1. {@code @Valid} 注解检查。用于标记需要级联校验的对象,例如: - * {@code void validateCompany(@Valid Company company)}。
  2. - *
  3. 其他携带 {@code @Constraint} 元注解的校验注解检查。例如: - * {@code void validateEmployee(@NotBlank String name, @Positive int age)}。
  4. + *
  5. {@code @Valid} 注解检查。用于标记需要级联校验的对象,例如: {@code void validateCompany(@Valid Company company)}。
  6. + *
  7. 其他携带 {@code @Constraint} 元注解的校验注解检查。例如: {@code void validateEmployee(@NotBlank String name, @Positive int + * age)}。
  8. *
- *

* * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation} * @return 如果属于 {@code javax.validation} 注解(即 @Valid 或携带 @Constraint),则返回 {@code true},否则返回 {@code false}。 diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index ffcaf785f..eb2142767 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -24,7 +24,7 @@ public class GroupValidateService { private static final Logger LOG = Logger.get(GroupValidateService.class); - // 学生年龄验证服务 + // 学生年龄验证服务。 @Component @Validated(ValidationTestData.StudentGroup.class) public static class StudentValidateService { @@ -36,7 +36,7 @@ public void validateStudentAge( } } - // 教师年龄验证服务 + // 教师年龄验证服务。 @Component @Validated(ValidationTestData.TeacherGroup.class) public static class TeacherValidateService { @@ -48,7 +48,7 @@ public void validateTeacherAge( } } - // 高级分组验证服务 + // 高级分组验证服务。 @Component @Validated(ValidationTestData.AdvancedGroup.class) public static class AdvancedValidateService { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index d804f5957..e70536cd1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -92,35 +92,35 @@ public void foo2(@Valid Company company) { /** * 测试 NotNull 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testNotNull(@NotNull String value) {} /** * 测试 NotEmpty 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testNotEmpty(@NotEmpty String value) {} /** * 测试 NotBlank 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testNotBlank(@NotBlank String value) {} /** * 测试 Null 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testNull(@Null String value) {} /** * 测试 Size 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testSize(@Size(min = 2, max = 10) String value) {} @@ -148,14 +148,14 @@ public void testMax(@Max(100) int value) {} /** * 测试 DecimalMin 约束注解。 * - * @param value 表示输入的 {@code BigDecimal}。 + * @param value 表示输入的 {@link BigDecimal}。 */ public void testDecimalMin(@DecimalMin("10.5") BigDecimal value) {} /** * 测试 DecimalMax 约束注解。 * - * @param value 表示输入的 {@code BigDecimal}。 + * @param value 表示输入的 {@link BigDecimal}。 */ public void testDecimalMax(@DecimalMax("100.5") BigDecimal value) {} @@ -190,49 +190,49 @@ public void testNegativeOrZero(@NegativeOrZero int value) {} /** * 测试 Digits 约束注解。 * - * @param value 表示输入的 {@code BigDecimal}。 + * @param value 表示输入的 {@link BigDecimal}。 */ public void testDigits(@Digits(integer = 3, fraction = 2) BigDecimal value) {} /** * 测试 Past 约束注解。 * - * @param value 表示输入的 {@code LocalDate}。 + * @param value 表示输入的 {@link LocalDate}。 */ public void testPast(@Past LocalDate value) {} /** * 测试 PastOrPresent 约束注解。 * - * @param value 表示输入的 {@code LocalDate}。 + * @param value 表示输入的 {@link LocalDate}。 */ public void testPastOrPresent(@PastOrPresent LocalDate value) {} /** * 测试 Future 约束注解。 * - * @param value 表示输入的 {@code LocalDate}。 + * @param value 表示输入的 {@link LocalDate}。 */ public void testFuture(@Future LocalDate value) {} /** * 测试 FutureOrPresent 约束注解。 * - * @param value 表示输入的 {@code LocalDate}。 + * @param value 表示输入的 {@link LocalDate}。 */ public void testFutureOrPresent(@FutureOrPresent LocalDate value) {} /** * 测试 Pattern 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testPattern(@Pattern(regexp = "^[a-zA-Z]+$") String value) {} /** * 测试 Email 约束注解。 * - * @param value 表示输入的 {@code String}。 + * @param value 表示输入的 {@link String}。 */ public void testEmail(@Email String value) {} @@ -267,7 +267,7 @@ public void testRange(@Range(min = 10, max = 100, message = "需要在10和100 /** * 测试 BigDecimal 类型的Range约束注解。 * - * @param value 表示输入的 {@code BigDecimal}。 + * @param value 表示输入的 {@link BigDecimal}。 */ public void testRangeBigDecimal(@Range(min = 10, max = 100, message = "需要在10和100之间") BigDecimal value) {} @@ -292,7 +292,7 @@ public void validateAge(@Positive(message = "必须是正数") int age) { /** * 验证姓名和年龄。 * - * @param name 表示输入的 {@code String}。 + * @param name 表示输入的 {@link String}。 * @param age 表示输入的 {@code int}。 */ public void validateNameAndAge(@NotBlank String name, @Positive int age) { @@ -362,7 +362,7 @@ public void validateNestedEmployeeList(List> nestedList) { /** * 验证员工映射。 * - * @param employeeMap 表示输入的 {@link Map}。 + * @param employeeMap 表示输入的 {@code Map}。 */ public void validateEmployeeMap(@Valid Map employeeMap) { LOG.debug("Validating employee map: {}", employeeMap); @@ -371,7 +371,7 @@ public void validateEmployeeMap(@Valid Map employeeMap) { /** * 验证员工数据映射。 * - * @param map 表示输入的 {@link Map}。 + * @param map 表示输入的 {@code Map}。 */ public void validateEmployeeDataMap(@Valid Map map) { LOG.debug("Validating employee data map: {}", map); @@ -380,7 +380,7 @@ public void validateEmployeeDataMap(@Valid Map map /** * 验证嵌套员工数据映射。 * - * @param nestedMap 表示输入的 {@link Map>}。 + * @param nestedMap 表示输入的 {@code Map>}。 */ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map> nestedMap) { LOG.debug("Validating nested employee data map: {}", nestedMap); @@ -389,7 +389,7 @@ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map>}。 + * @param listOfMaps 表示输入的 {@code List>}。 */ public void validateEmployeeMapList(List> listOfMaps) { LOG.debug("Validating employee map list: {}", listOfMaps); @@ -398,7 +398,7 @@ public void validateEmployeeMapList(List> listOfMap /** * 验证员工数据列表映射。 * - * @param map 表示输入的 {@link Map>}。 + * @param map 表示输入的 {@code Map>}。 */ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { LOG.debug("Validating employee data list map: {}", map); @@ -407,7 +407,7 @@ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid Validat /** * 验证公司列表。 * - * @param companies 表示输入的 {@link List}。 + * @param companies 表示输入的 {@code List}。 */ public void validateCompanyList(@Valid List companies) { LOG.debug("Validating company list: {}", companies); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index 9a8180205..df1880909 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -52,10 +52,8 @@ public interface TeacherGroup {} @AssertTrue(message = "必须同意条款") private Boolean agreed; - // 构造函数 public ValidationTestData() {} - // Getters and Setters public String getName() { return name; } From df84b2892a8872889654d2d125b21e6dbb95d07b Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Mon, 18 Aug 2025 14:02:33 +0800 Subject: [PATCH 16/23] =?UTF-8?q?[fit]=20=E5=AE=9E=E7=8E=B0=E5=8F=AF?= =?UTF-8?q?=E6=98=BE=E5=BC=8F=E4=BC=A0=E9=80=92=E5=9C=B0=E5=8C=BA=E7=9A=84?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/LocaleMessageInterpolator.java | 62 +++++++++++++++++++ .../validation/ValidationHandler.java | 15 ++++- .../validation/ValidationHandlerTest.java | 5 +- .../validation/LocaleMessageInterpolator.java | 62 +++++++++++++++++++ .../validation/ValidationHandler.java | 15 ++++- .../validation/ValidationHandlerTest.java | 5 +- 6 files changed, 152 insertions(+), 12 deletions(-) create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java new file mode 100644 index 000000000..4b3b3c03d --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation; + +import jakarta.validation.MessageInterpolator; + +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; + +import java.util.Locale; + +/** + * 地区消息插值器。 + *

+ * 作为 Jakarta 消息插值器的代理类,提供地区设置能力。 + *

+ * + * @author 阮睿 + * @since 2025-08-18 + */ +public class LocaleMessageInterpolator implements MessageInterpolator { + private final MessageInterpolator target; + + private Locale locale; + + public LocaleMessageInterpolator(MessageInterpolator target) { + this.target = target; + this.locale = Locale.getDefault(); + } + + public LocaleMessageInterpolator(Locale locale) { + this.locale = locale; + this.target = new ParameterMessageInterpolator(); + } + + public LocaleMessageInterpolator(MessageInterpolator target, Locale locale) { + this.target = target; + this.locale = locale; + } + + public LocaleMessageInterpolator() { + locale = Locale.getDefault(); + target = new ParameterMessageInterpolator(); + } + + @Override + public String interpolate(String messageTemplate, Context context) { + return target.interpolate(messageTemplate, context, this.locale); + } + + @Override + public String interpolate(String messageTemplate, Context context, Locale locale) { + return target.interpolate(messageTemplate, context, this.locale); + } + + public void setLocale(Locale locale) { + this.locale = locale; + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 04b397052..3840e8524 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -20,13 +20,13 @@ import modelengine.fitframework.ioc.annotation.PreDestroy; import org.hibernate.validator.HibernateValidator; -import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedParameterizedType; import java.lang.reflect.AnnotatedType; import java.lang.reflect.Parameter; import java.util.Arrays; +import java.util.Locale; import java.util.Set; /** @@ -43,16 +43,27 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; + private LocaleMessageInterpolator messageInterpolator; public ValidationHandler() { + messageInterpolator = new LocaleMessageInterpolator(); this.validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() - .messageInterpolator(new ParameterMessageInterpolator()) + .messageInterpolator(messageInterpolator) .failFast(false) .buildValidatorFactory(); this.validator = validatorFactory.getValidator(); } + /** + * 设置校验信息语言。 + * + * @param locale 校验语言 {@link Locale}。 + */ + public void setLocale(Locale locale) { + this.messageInterpolator.setLocale(locale); + } + /** * 方法参数校验处理。 * diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 9fa28acd6..9791b4566 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -49,10 +49,6 @@ * @since 2025-07-18 */ public class ValidationHandlerTest { - static { - Locale.setDefault(Locale.CHINA); - } - private final ValidateService validateService = mock(ValidateService.class); private final BeanContainer beanContainer = mock(BeanContainer.class); private final FitRuntime fitRuntime = mock(FitRuntime.class); @@ -62,6 +58,7 @@ public class ValidationHandlerTest { @BeforeEach void setUp() { + handler.setLocale(Locale.CHINA); when(validated.value()).thenReturn(new Class[0]); when(fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); when(beanContainer.runtime()).thenReturn(fitRuntime); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java new file mode 100644 index 000000000..27bdaa8e8 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java @@ -0,0 +1,62 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation; + +import javax.validation.MessageInterpolator; + +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; + +import java.util.Locale; + +/** + * 地区消息插值器。 + *

+ * 作为 Jakarta 消息插值器的代理类,提供地区设置能力。 + *

+ * + * @author 阮睿 + * @since 2025-08-18 + */ +public class LocaleMessageInterpolator implements MessageInterpolator { + private final MessageInterpolator target; + + private Locale locale; + + public LocaleMessageInterpolator(MessageInterpolator target) { + this.target = target; + this.locale = Locale.getDefault(); + } + + public LocaleMessageInterpolator(Locale locale) { + this.locale = locale; + this.target = new ParameterMessageInterpolator(); + } + + public LocaleMessageInterpolator(MessageInterpolator target, Locale locale) { + this.target = target; + this.locale = locale; + } + + public LocaleMessageInterpolator() { + locale = Locale.getDefault(); + target = new ParameterMessageInterpolator(); + } + + @Override + public String interpolate(String messageTemplate, Context context) { + return target.interpolate(messageTemplate, context, this.locale); + } + + @Override + public String interpolate(String messageTemplate, Context context, Locale locale) { + return target.interpolate(messageTemplate, context, this.locale); + } + + public void setLocale(Locale locale) { + this.locale = locale; + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index deae481aa..fa30b2cbf 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -20,13 +20,13 @@ import modelengine.fitframework.ioc.annotation.PreDestroy; import org.hibernate.validator.HibernateValidator; -import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedParameterizedType; import java.lang.reflect.AnnotatedType; import java.lang.reflect.Parameter; import java.util.Arrays; +import java.util.Locale; import java.util.Set; /** @@ -43,16 +43,27 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; + private LocaleMessageInterpolator messageInterpolator; public ValidationHandler() { + this.messageInterpolator = new LocaleMessageInterpolator(); this.validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() - .messageInterpolator(new ParameterMessageInterpolator()) + .messageInterpolator(messageInterpolator) .failFast(false) .buildValidatorFactory(); this.validator = validatorFactory.getValidator(); } + /** + * 设置校验信息语言。 + * + * @param locale 校验语言 {@link Locale}。 + */ + public void setLocale(Locale locale) { + this.messageInterpolator.setLocale(locale); + } + /** * 方法参数校验处理。 * diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index f4fe5cb6a..cb97d97c9 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -50,10 +50,6 @@ * @since 2025-07-18 */ public class ValidationHandlerTest { - static { - Locale.setDefault(Locale.CHINA); - } - private final ValidateService validateService = mock(ValidateService.class); private final BeanContainer beanContainer = mock(BeanContainer.class); private final FitRuntime fitRuntime = mock(FitRuntime.class); @@ -63,6 +59,7 @@ public class ValidationHandlerTest { @BeforeEach void setUp() { + handler.setLocale(Locale.CHINA); when(validated.value()).thenReturn(new Class[0]); when(fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); when(beanContainer.runtime()).thenReturn(fitRuntime); From 9c64f7bd5960d78a560e71ac74ca56621ca85453 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Tue, 19 Aug 2025 18:55:03 +0800 Subject: [PATCH 17/23] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/LocaleMessageInterpolator.java | 28 +++++++++++++++++-- .../validation/ValidationHandler.java | 24 ++++++++++------ .../fitframework/validation/data/Company.java | 8 ++++++ .../validation/data/Employee.java | 9 ++++++ .../validation/data/GroupValidateService.java | 19 +++++++++++-- .../validation/data/ValidateService.java | 25 +++++++++-------- .../validation/LocaleMessageInterpolator.java | 28 +++++++++++++++++-- .../validation/ValidationHandler.java | 26 ++++++++++------- .../fitframework/validation/data/Company.java | 8 ++++++ .../validation/data/Employee.java | 9 ++++++ .../validation/data/GroupValidateService.java | 19 +++++++++++-- .../validation/data/ValidateService.java | 25 +++++++++-------- 12 files changed, 177 insertions(+), 51 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java index 4b3b3c03d..f51beec04 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java @@ -26,24 +26,43 @@ public class LocaleMessageInterpolator implements MessageInterpolator { private Locale locale; + /** + * 构造函数,使用指定的目标消息插值器初始化实例。 + * + * @param target 目标消息插值器 {@link MessageInterpolator}。 + */ public LocaleMessageInterpolator(MessageInterpolator target) { this.target = target; this.locale = Locale.getDefault(); } + /** + * 构造函数,使用指定的地区初始化实例。 + * + * @param locale 指定的地区 {@link Locale}。 + */ public LocaleMessageInterpolator(Locale locale) { this.locale = locale; this.target = new ParameterMessageInterpolator(); } + /** + * 构造函数,使用指定的目标消息插值器和地区初始化实例。 + * + * @param target 被代理的目标消息插值器 {@link MessageInterpolator}。 + * @param locale 指示当前消息插值器要使用语言的相关地区 {@link Locale}。 + */ public LocaleMessageInterpolator(MessageInterpolator target, Locale locale) { this.target = target; this.locale = locale; } + /** + * 构造函数,使用默认地区初始化实例。 + */ public LocaleMessageInterpolator() { - locale = Locale.getDefault(); - target = new ParameterMessageInterpolator(); + this.locale = Locale.getDefault(); + this.target = new ParameterMessageInterpolator(); } @Override @@ -56,6 +75,11 @@ public String interpolate(String messageTemplate, Context context, Locale locale return target.interpolate(messageTemplate, context, this.locale); } + /** + * 设置地区。 + * + * @param locale 指示当前消息插值器要使用语言的相关地区 {@link Locale}。 + */ public void setLocale(Locale locale) { this.locale = locale; } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 3840e8524..ad3e41a54 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -94,7 +94,7 @@ public void close() { /** * 检查方法参数是否包含 {@code jakarta.validation} 校验注解。 * - * @param parameters 方法参数数组 {@link Parameter}{@code []}。 + * @param parameters 表示可能携带校验注解的方法参数数组 {@link Parameter}{@code []}。 * @return 如果包含 {@code jakarta.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { @@ -104,7 +104,7 @@ private boolean hasJakartaConstraintAnnotations(Parameter[] parameters) { /** * 检查参数及其泛型类型参数是否包含校验注解。 * - * @param parameter 方法参数 {@link Parameter}。 + * @param parameter 表示可能携带校验注解的方法参数 {@link Parameter}。 * @return 如果包含 {@code jakarta.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { @@ -112,9 +112,9 @@ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { } /** - * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解。 + * 判断参数类型,解析参数本身注解或其泛型类型参数注解。 * - * @param annotatedType 参数注解类型 {@link AnnotatedType}。 + * @param annotatedType 表示待检查的参数类型 {@link AnnotatedType}。 * @return 如果包含 {@code jakarta.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { @@ -135,13 +135,19 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { /** *

- * 检查注解是否属于 {@code jakarta.validation} 注解。 + * 检查注解是否属于 {@code jakarta.validation} 注解。 + *

*

- * 由于存在嵌套校验的情况, {@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + * 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + *

*
    - *
  1. {@code @Valid} 注解检查。用于标记需要级联校验的对象,例如: {@code void validateCompany(@Valid Company company)}。
  2. - *
  3. 其他携带 {@code @Constraint} 元注解的校验注解检查。例如: {@code void validateEmployee(@NotBlank String name, @Positive int - * age)}。
  4. + *
  5. + * {@code @Valid} 注解检查。用于标记需要级联校验的对象,例如:{@code void validateCompany(@Valid Company company)}。 + *
  6. + *
  7. + * 其他携带 {@code @Constraint} 元注解的校验注解检查。例如:{@code void validateEmployee(@NotBlank String name, @Positive + * int)}。 + *
  8. *
* * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java index d80b6b783..d78be0a0a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -23,8 +23,16 @@ public class Company { @Valid private List employees; + /** + * 默认构造函数。 + */ public Company() {} + /** + * 构造函数。 + * + * @param employees 表示雇员列表的 {@link List}{@code <}{@link Employee}{@code >}。 + */ public Company(List employees) { this.employees = employees; } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java index b4488e3c9..e56f7f650 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -23,8 +23,17 @@ public class Employee { @Min(value = 18, message = "年龄必须大于等于18") private int age; + /** + * 默认构造函数。 + */ public Employee() {} + /** + * 构造函数。 + * + * @param name 姓名 {@link String}。 + * @param age 年龄 {@code int} + */ public Employee(String name, int age) { this.name = name; this.age = age; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index ffa8c0674..15b0fa905 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -23,10 +23,14 @@ public class GroupValidateService { private static final Logger LOG = Logger.get(GroupValidateService.class); - // 学生年龄验证服务。 @Component @Validated(ValidationTestData.StudentGroup.class) public static class StudentValidateService { + /** + * 验证学生年龄。 + * + * @param age 年龄 {@code int} + */ public void validateStudentAge( @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) @Max( value = 20, message = "范围要在7~20之内", @@ -35,10 +39,14 @@ public void validateStudentAge( } } - // 教师年龄验证服务。 @Component @Validated(ValidationTestData.TeacherGroup.class) public static class TeacherValidateService { + /** + * 验证教师年龄。 + * + * @param age 年龄 {@code int} + */ public void validateTeacherAge( @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) @Max( value = 65, message = "范围要在22~65之内", @@ -51,8 +59,13 @@ public void validateTeacherAge( @Component @Validated(ValidationTestData.AdvancedGroup.class) public static class AdvancedValidateService { + /** + * 验证高级分组数据。 + * + * @param data 用于测试复杂对象验证的数据 {@link ValidationTestData} + */ public void validateAdvancedGroup(@Valid ValidationTestData data) { LOG.debug("Validating advanced group data: {}", data); } } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index 0b2745cf0..b03e87dd5 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -126,7 +126,7 @@ public void testSize(@Size(min = 2, max = 10) String value) {} /** * 测试 List 的 Size 约束注解。 * - * @param value 表示输入的 {@code List}。 + * @param value 表示输入的 {@link List}{@code <}{@link String}{@code >}。 */ public void testSizeList(@Size(min = 1, max = 3) List value) {} @@ -343,7 +343,7 @@ public void validateCompany(@Valid Company company) { /** * 验证员工列表。 * - * @param employees 表示输入的 {@link List}。 + * @param employees 表示输入的 {@link List}{@code <}{@link Employee}{@code >}。 */ public void validateEmployeeList(List<@Valid Employee> employees) { LOG.debug("Validating employee list: {}", employees); @@ -352,7 +352,7 @@ public void validateEmployeeList(List<@Valid Employee> employees) { /** * 验证嵌套员工列表。 * - * @param nestedList 表示输入的 {@link List>}。 + * @param nestedList 表示输入的 {@link List}{@code <}{@link List}{@code <}{@link Employee}{@code >}{@code >}}。 */ public void validateNestedEmployeeList(List> nestedList) { LOG.debug("Validating nested employee list: {}", nestedList); @@ -361,7 +361,7 @@ public void validateNestedEmployeeList(List> nestedList) { /** * 验证员工映射。 * - * @param employeeMap 表示输入的 {@code Map}。 + * @param employeeMap 表示输入的 {@link Map}{@code <}{@link String}{@code , }{@link Employee}{@code >}。 */ public void validateEmployeeMap(@Valid Map employeeMap) { LOG.debug("Validating employee map: {}", employeeMap); @@ -370,7 +370,7 @@ public void validateEmployeeMap(@Valid Map employeeMap) { /** * 验证员工数据映射。 * - * @param map 表示输入的 {@code Map}。 + * @param map 表示输入的 {@link Map}{@code <}{@link Employee}{@code , }{@link ValidationTestData}>。 */ public void validateEmployeeDataMap(@Valid Map map) { LOG.debug("Validating employee data map: {}", map); @@ -379,7 +379,9 @@ public void validateEmployeeDataMap(@Valid Map map /** * 验证嵌套员工数据映射。 * - * @param nestedMap 表示输入的 {@code Map>}。 + * @param nestedMap 表示输入的 + * {@link Map}{@code <}{@link Employee}{@code , }{@link Map}{@code <}{@link String}{@code , }{@link + * ValidationTestData}{@code >}{@code >}。 */ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map> nestedMap) { LOG.debug("Validating nested employee data map: {}", nestedMap); @@ -388,7 +390,8 @@ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map>}。 + * @param listOfMaps 表示输入的 {@link List}{@code <}{@link Map}{@code <}{@link String}{@code , + * }{@link Employee}{@code >}{@code >}。 */ public void validateEmployeeMapList(List> listOfMaps) { LOG.debug("Validating employee map list: {}", listOfMaps); @@ -397,7 +400,7 @@ public void validateEmployeeMapList(List> listOfMap /** * 验证员工数据列表映射。 * - * @param map 表示输入的 {@code Map>}。 + * @param map 表示输入的 {@link Map}{@code <}{@link Employee}{@code , }{@link List}{@code <}{@link ValidationTestData}{@code >}{}。 */ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { LOG.debug("Validating employee data list map: {}", map); @@ -406,7 +409,7 @@ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid Validat /** * 验证公司列表。 * - * @param companies 表示输入的 {@code List}。 + * @param companies 表示输入的 {@link List}{@code <}{@link Company}{@code >}。 */ public void validateCompanyList(@Valid List companies) { LOG.debug("Validating company list: {}", companies); @@ -425,8 +428,8 @@ public void validateMixed(@Positive int value, @Valid Employee employee) { /** * 验证混合集合数据。 * - * @param list1 表示输入的 {@code List}。 - * @param list2 表示输入的 {@code List}。 + * @param list1 表示输入的 {@link List}{@code <}{@link String}{@code >}。 + * @param list2 表示输入的 {@link List}{@code <}{@link String}{@code >}。 */ public void validateMixedCollections(@NotNull List list1, @NotEmpty List list2) { LOG.debug("Validating mixed collections: {} and {}", list1, list2); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java index 27bdaa8e8..816e3c5d2 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java @@ -26,24 +26,43 @@ public class LocaleMessageInterpolator implements MessageInterpolator { private Locale locale; + /** + * 构造函数,使用指定的目标消息插值器初始化实例。 + * + * @param target 目标消息插值器 {@link MessageInterpolator}。 + */ public LocaleMessageInterpolator(MessageInterpolator target) { this.target = target; this.locale = Locale.getDefault(); } + /** + * 构造函数,使用指定的地区初始化实例。 + * + * @param locale 指定的地区 {@link Locale}。 + */ public LocaleMessageInterpolator(Locale locale) { this.locale = locale; this.target = new ParameterMessageInterpolator(); } + /** + * 构造函数,使用指定的目标消息插值器和地区初始化实例。 + * + * @param target 被代理的目标消息插值器 {@link MessageInterpolator}。 + * @param locale 指示当前消息插值器要使用语言的相关地区 {@link Locale}。 + */ public LocaleMessageInterpolator(MessageInterpolator target, Locale locale) { this.target = target; this.locale = locale; } + /** + * 构造函数,使用默认地区初始化实例。 + */ public LocaleMessageInterpolator() { - locale = Locale.getDefault(); - target = new ParameterMessageInterpolator(); + this.locale = Locale.getDefault(); + this.target = new ParameterMessageInterpolator(); } @Override @@ -56,6 +75,11 @@ public String interpolate(String messageTemplate, Context context, Locale locale return target.interpolate(messageTemplate, context, this.locale); } + /** + * 设置地区。 + * + * @param locale 指示当前消息插值器要使用语言的相关地区 {@link Locale}。 + */ public void setLocale(Locale locale) { this.locale = locale; } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index fa30b2cbf..9d1c81000 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -94,7 +94,7 @@ public void close() { /** * 检查方法参数是否包含 {@code javax.validation} 校验注解。 * - * @param parameters 方法参数数组 {@link Parameter}{@code []}。 + * @param parameters 表示可能携带校验注解的方法参数数组 {@link Parameter}{@code []}。 * @return 如果包含 {@code javax.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { @@ -104,7 +104,7 @@ private boolean hasJavaxConstraintAnnotations(Parameter[] parameters) { /** * 检查参数及其泛型类型参数是否包含校验注解。 * - * @param parameter 方法参数数组 {@link Parameter}。 + * @param parameter 表示可能携带校验注解的方法参数 {@link Parameter}。 * @return 如果包含 {@code javax.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { @@ -112,9 +112,9 @@ private boolean hasConstraintAnnotationsInParameter(Parameter parameter) { } /** - * 判断参数注解类型,解析参数本身注解及其泛型类型参数注解。 + * 判断参数类型,解析参数本身注解或其泛型类型参数注解。 * - * @param annotatedType 参数注解类型 {@link AnnotatedType}。 + * @param annotatedType 表示待检查的参数类型 {@link AnnotatedType}。 * @return 如果包含 {@code javax.validation} 标注的校验注解则返回 {@code true},否则返回 {@code false}。 */ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { @@ -135,13 +135,19 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { /** *

- * 检查注解是否属于 {@code javax.validation} 注解。 + * 检查注解是否属于 {@code jakarta.validation} 注解。 + *

*

- * 由于存在嵌套校验的情况, {@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + * 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + *

*
    - *
  1. {@code @Valid} 注解检查。用于标记需要级联校验的对象,例如: {@code void validateCompany(@Valid Company company)}。
  2. - *
  3. 其他携带 {@code @Constraint} 元注解的校验注解检查。例如: {@code void validateEmployee(@NotBlank String name, @Positive int - * age)}。
  4. + *
  5. + * {@code @Valid} 注解检查。用于标记需要级联校验的对象,例如:{@code void validateCompany(@Valid Company company)}。 + *
  6. + *
  7. + * 其他携带 {@code @Constraint} 元注解的校验注解检查。例如:{@code void validateEmployee(@NotBlank String name, @Positive + * int)}。 + *
  8. *
* * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation} @@ -152,7 +158,7 @@ private boolean isJavaxConstraintAnnotation(Annotation annotation) { if (annotation.annotationType().getName().equals("javax.validation.Valid")) { return true; } - // 检查 javax.validation.constraints, org.hibernate.validator.constraints 包下的注解或者用户根据 javax 标准自行实现的注解检查。。 + // 检查 javax.validation.constraints, org.hibernate.validator.constraints 包下的注解或者用户根据 javax 标准自行实现的注解检查。 // 通过 Constraint 注解检查当前注解是否为校验注解。 Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); return Arrays.stream(metaAnnotations).anyMatch(metaAnnotation -> { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java index a7b74e335..8836fa01a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Company.java @@ -23,8 +23,16 @@ public class Company { @Valid private List employees; + /** + * 默认构造函数。 + */ public Company() {} + /** + * 构造函数。 + * + * @param employees 表示雇员列表的 {@link List}{@code <}{@link Employee}{@code >}。 + */ public Company(List employees) { this.employees = employees; } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java index f5dce43dd..c8178f0b4 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -23,8 +23,17 @@ public class Employee { @Min(value = 18, message = "年龄必须大于等于18") private int age; + /** + * 默认构造函数。 + */ public Employee() {} + /** + * 构造函数。 + * + * @param name 姓名 {@link String}。 + * @param age 年龄 {@code int} + */ public Employee(String name, int age) { this.name = name; this.age = age; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index eb2142767..fc2a8a15d 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -24,10 +24,14 @@ public class GroupValidateService { private static final Logger LOG = Logger.get(GroupValidateService.class); - // 学生年龄验证服务。 @Component @Validated(ValidationTestData.StudentGroup.class) public static class StudentValidateService { + /** + * 验证学生年龄。 + * + * @param age 年龄 {@code int} + */ public void validateStudentAge( @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) @Max( value = 20, message = "范围要在7~20之内", @@ -36,10 +40,14 @@ public void validateStudentAge( } } - // 教师年龄验证服务。 @Component @Validated(ValidationTestData.TeacherGroup.class) public static class TeacherValidateService { + /** + * 验证教师年龄。 + * + * @param age 年龄 {@code int} + */ public void validateTeacherAge( @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) @Max( value = 65, message = "范围要在22~65之内", @@ -52,8 +60,13 @@ public void validateTeacherAge( @Component @Validated(ValidationTestData.AdvancedGroup.class) public static class AdvancedValidateService { + /** + * 验证高级分组数据。 + * + * @param data 用于测试复杂对象验证的数据 {@link ValidationTestData} + */ public void validateAdvancedGroup(@Valid ValidationTestData data) { LOG.debug("Validating advanced group data: {}", data); } } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index e70536cd1..a35bc5c1a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -127,7 +127,7 @@ public void testSize(@Size(min = 2, max = 10) String value) {} /** * 测试 List 的 Size 约束注解。 * - * @param value 表示输入的 {@code List}。 + * @param value 表示输入的 {@link List}{@code <}{@link String}{@code >}。 */ public void testSizeList(@Size(min = 1, max = 3) List value) {} @@ -344,7 +344,7 @@ public void validateCompany(@Valid Company company) { /** * 验证员工列表。 * - * @param employees 表示输入的 {@link List}。 + * @param employees 表示输入的 {@link List}{@code <}{@link Employee}{@code >}。 */ public void validateEmployeeList(List<@Valid Employee> employees) { LOG.debug("Validating employee list: {}", employees); @@ -353,7 +353,7 @@ public void validateEmployeeList(List<@Valid Employee> employees) { /** * 验证嵌套员工列表。 * - * @param nestedList 表示输入的 {@link List>}。 + * @param nestedList 表示输入的 {@link List}{@code <}{@link List}{@code <}{@link Employee}{@code >}{@code >}}。 */ public void validateNestedEmployeeList(List> nestedList) { LOG.debug("Validating nested employee list: {}", nestedList); @@ -362,7 +362,7 @@ public void validateNestedEmployeeList(List> nestedList) { /** * 验证员工映射。 * - * @param employeeMap 表示输入的 {@code Map}。 + * @param employeeMap 表示输入的 {@link Map}{@code <}{@link String}{@code , }{@link Employee}{@code >}。 */ public void validateEmployeeMap(@Valid Map employeeMap) { LOG.debug("Validating employee map: {}", employeeMap); @@ -371,7 +371,7 @@ public void validateEmployeeMap(@Valid Map employeeMap) { /** * 验证员工数据映射。 * - * @param map 表示输入的 {@code Map}。 + * @param map 表示输入的 {@link Map}{@code <}{@link Employee}{@code , }{@link ValidationTestData}>。 */ public void validateEmployeeDataMap(@Valid Map map) { LOG.debug("Validating employee data map: {}", map); @@ -380,7 +380,9 @@ public void validateEmployeeDataMap(@Valid Map map /** * 验证嵌套员工数据映射。 * - * @param nestedMap 表示输入的 {@code Map>}。 + * @param nestedMap 表示输入的 + * {@link Map}{@code <}{@link Employee}{@code , }{@link Map}{@code <}{@link String}{@code , }{@link + * ValidationTestData}{@code >}{@code >}。 */ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map> nestedMap) { LOG.debug("Validating nested employee data map: {}", nestedMap); @@ -389,7 +391,8 @@ public void validateNestedEmployeeDataMap(Map<@Valid Employee, Map>}。 + * @param listOfMaps 表示输入的 {@link List}{@code <}{@link Map}{@code <}{@link String}{@code , + * }{@link Employee}{@code >}{@code >}。 */ public void validateEmployeeMapList(List> listOfMaps) { LOG.debug("Validating employee map list: {}", listOfMaps); @@ -398,7 +401,7 @@ public void validateEmployeeMapList(List> listOfMap /** * 验证员工数据列表映射。 * - * @param map 表示输入的 {@code Map>}。 + * @param map 表示输入的 {@link Map}{@code <}{@link Employee}{@code , }{@link List}{@code <}{@link ValidationTestData}{@code >}{}。 */ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { LOG.debug("Validating employee data list map: {}", map); @@ -407,7 +410,7 @@ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid Validat /** * 验证公司列表。 * - * @param companies 表示输入的 {@code List}。 + * @param companies 表示输入的 {@link List}{@code <}{@link Company}{@code >}。 */ public void validateCompanyList(@Valid List companies) { LOG.debug("Validating company list: {}", companies); @@ -426,8 +429,8 @@ public void validateMixed(@Positive int value, @Valid Employee employee) { /** * 验证混合集合数据。 * - * @param list1 表示输入的 {@code List}。 - * @param list2 表示输入的 {@code List}。 + * @param list1 表示输入的 {@link List}{@code <}{@link String}{@code >}。 + * @param list2 表示输入的 {@link List}{@code <}{@link String}{@code >}。 */ public void validateMixedCollections(@NotNull List list1, @NotEmpty List list2) { LOG.debug("Validating mixed collections: {} and {}", list1, list2); From 1adfa20813dbbbfa645174562c981a690e1b17fc Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Tue, 19 Aug 2025 19:56:45 +0800 Subject: [PATCH 18/23] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fitframework/validation/ValidationHandler.java | 2 +- .../modelengine/fitframework/validation/data/Employee.java | 2 +- .../fitframework/validation/data/GroupValidateService.java | 6 +++--- .../fitframework/validation/data/ValidateService.java | 3 ++- .../fitframework/validation/data/ValidationTestData.java | 2 +- .../fitframework/validation/ValidationHandler.java | 2 +- .../modelengine/fitframework/validation/data/Employee.java | 2 +- .../fitframework/validation/data/GroupValidateService.java | 6 +++--- .../fitframework/validation/data/ValidateService.java | 3 ++- .../fitframework/validation/data/ValidationTestData.java | 2 +- 10 files changed, 16 insertions(+), 14 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index ad3e41a54..a7af81936 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -150,7 +150,7 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { * * * - * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation} + * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation}。 * @return 如果属于 {@code jakarta.validation} 注解(即 @Valid 或携带 @Constraint),则返回 {@code true},否则返回 {@code false}。 */ private boolean isJakartaConstraintAnnotation(Annotation annotation) { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java index e56f7f650..dca119e3d 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -32,7 +32,7 @@ public Employee() {} * 构造函数。 * * @param name 姓名 {@link String}。 - * @param age 年龄 {@code int} + * @param age 年龄 {@code int}。 */ public Employee(String name, int age) { this.name = name; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index 15b0fa905..01323f314 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -29,7 +29,7 @@ public static class StudentValidateService { /** * 验证学生年龄。 * - * @param age 年龄 {@code int} + * @param age 年龄 {@code int}。 */ public void validateStudentAge( @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) @Max( @@ -45,7 +45,7 @@ public static class TeacherValidateService { /** * 验证教师年龄。 * - * @param age 年龄 {@code int} + * @param age 年龄 {@code int}。 */ public void validateTeacherAge( @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) @Max( @@ -62,7 +62,7 @@ public static class AdvancedValidateService { /** * 验证高级分组数据。 * - * @param data 用于测试复杂对象验证的数据 {@link ValidationTestData} + * @param data 用于测试复杂对象验证的数据 {@link ValidationTestData}。 */ public void validateAdvancedGroup(@Valid ValidationTestData data) { LOG.debug("Validating advanced group data: {}", data); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index b03e87dd5..075146232 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -400,7 +400,8 @@ public void validateEmployeeMapList(List> listOfMap /** * 验证员工数据列表映射。 * - * @param map 表示输入的 {@link Map}{@code <}{@link Employee}{@code , }{@link List}{@code <}{@link ValidationTestData}{@code >}{}。 + * @param map 表示输入的 + * {@link Map}{@code <}{@link Employee}{@code , }{@link List}{@code <}{@link ValidationTestData}{@code >}。 */ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { LOG.debug("Validating employee data list map: {}", map); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index b0af3c0e4..0d7e3f0f8 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -22,7 +22,7 @@ * @since 2025-07-18 */ public class ValidationTestData { - // 分组接口定义 + // 分组接口定义。 public interface AdvancedGroup {} public interface StudentGroup {} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 9d1c81000..59105b1c2 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -150,7 +150,7 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { * * * - * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation} + * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation}。 * @return 如果属于 {@code javax.validation} 注解(即 @Valid 或携带 @Constraint),则返回 {@code true},否则返回 {@code false}。 */ private boolean isJavaxConstraintAnnotation(Annotation annotation) { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java index c8178f0b4..19c164205 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -32,7 +32,7 @@ public Employee() {} * 构造函数。 * * @param name 姓名 {@link String}。 - * @param age 年龄 {@code int} + * @param age 年龄 {@code int}。 */ public Employee(String name, int age) { this.name = name; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index fc2a8a15d..036c267f8 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -30,7 +30,7 @@ public static class StudentValidateService { /** * 验证学生年龄。 * - * @param age 年龄 {@code int} + * @param age 年龄 {@code int}。 */ public void validateStudentAge( @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) @Max( @@ -46,7 +46,7 @@ public static class TeacherValidateService { /** * 验证教师年龄。 * - * @param age 年龄 {@code int} + * @param age 年龄 {@code int}。 */ public void validateTeacherAge( @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) @Max( @@ -63,7 +63,7 @@ public static class AdvancedValidateService { /** * 验证高级分组数据。 * - * @param data 用于测试复杂对象验证的数据 {@link ValidationTestData} + * @param data 用于测试复杂对象验证的数据 {@link ValidationTestData}。 */ public void validateAdvancedGroup(@Valid ValidationTestData data) { LOG.debug("Validating advanced group data: {}", data); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index a35bc5c1a..b8704becf 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -401,7 +401,8 @@ public void validateEmployeeMapList(List> listOfMap /** * 验证员工数据列表映射。 * - * @param map 表示输入的 {@link Map}{@code <}{@link Employee}{@code , }{@link List}{@code <}{@link ValidationTestData}{@code >}{}。 + * @param map 表示输入的 + * {@link Map}{@code <}{@link Employee}{@code , }{@link List}{@code <}{@link ValidationTestData}{@code >}。 */ public void validateEmployeeDataListMap(Map<@Valid Employee, List<@Valid ValidationTestData>> map) { LOG.debug("Validating employee data list map: {}", map); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index df1880909..2341d2501 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -22,7 +22,7 @@ * @since 2025-07-18 */ public class ValidationTestData { - // 分组接口定义 + // 分组接口定义。 public interface AdvancedGroup {} public interface StudentGroup {} From dfb34d3f7a3d6f61acd32f4e1a7a599d7c29d35d Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Tue, 19 Aug 2025 20:13:31 +0800 Subject: [PATCH 19/23] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fitframework/validation/ValidationHandler.java | 4 +--- .../modelengine/fitframework/validation/data/Employee.java | 4 ++-- .../fitframework/validation/data/GroupValidateService.java | 4 ++-- .../fitframework/validation/ValidationHandler.java | 4 +--- .../modelengine/fitframework/validation/data/Employee.java | 4 ++-- .../fitframework/validation/data/GroupValidateService.java | 4 ++-- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index a7af81936..829419f02 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -134,9 +134,7 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { } /** - *

- * 检查注解是否属于 {@code jakarta.validation} 注解。 - *

+ * 检查注解是否属于 {@code jakarta.validation} 注解。 *

* 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: *

diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java index dca119e3d..d5775b2a9 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -31,8 +31,8 @@ public Employee() {} /** * 构造函数。 * - * @param name 姓名 {@link String}。 - * @param age 年龄 {@code int}。 + * @param name 表示姓名的 {@link String}。 + * @param age 表示年龄的 {@code int}。 */ public Employee(String name, int age) { this.name = name; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index 01323f314..bba16b88b 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -29,7 +29,7 @@ public static class StudentValidateService { /** * 验证学生年龄。 * - * @param age 年龄 {@code int}。 + * @param age 表示年龄的 {@code int}。 */ public void validateStudentAge( @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) @Max( @@ -45,7 +45,7 @@ public static class TeacherValidateService { /** * 验证教师年龄。 * - * @param age 年龄 {@code int}。 + * @param age 表示年龄的 {@code int}。 */ public void validateTeacherAge( @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) @Max( diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 59105b1c2..199956f32 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -134,9 +134,7 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { } /** - *

- * 检查注解是否属于 {@code jakarta.validation} 注解。 - *

+ * 检查注解是否属于 {@code javax.validation} 注解。 *

* 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: *

diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java index 19c164205..cd0db61b1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -31,8 +31,8 @@ public Employee() {} /** * 构造函数。 * - * @param name 姓名 {@link String}。 - * @param age 年龄 {@code int}。 + * @param name 表示姓名的 {@link String}。 + * @param age 表示年龄的 {@code int}。 */ public Employee(String name, int age) { this.name = name; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index 036c267f8..d299bdfd5 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -30,7 +30,7 @@ public static class StudentValidateService { /** * 验证学生年龄。 * - * @param age 年龄 {@code int}。 + * @param age 表示年龄的 {@code int}。 */ public void validateStudentAge( @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) @Max( @@ -46,7 +46,7 @@ public static class TeacherValidateService { /** * 验证教师年龄。 * - * @param age 年龄 {@code int}。 + * @param age 表示年龄的 {@code int}。 */ public void validateTeacherAge( @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) @Max( From 7e080f6ec4a39c0f44f5adca90fa942ab3802481 Mon Sep 17 00:00:00 2001 From: jiyujie Date: Tue, 19 Aug 2025 21:10:34 +0800 Subject: [PATCH 20/23] polish code --- .../validation/LocaleMessageInterpolator.java | 10 +- .../validation/ValidationHandler.java | 20 ++- .../validation/ValidationHandlerTest.java | 142 +++++++++--------- .../validation/data/Employee.java | 7 +- .../validation/data/ValidationTestData.java | 42 +++++- .../validation/LocaleMessageInterpolator.java | 18 +-- .../validation/ValidationHandler.java | 35 +++-- .../validation/ValidationHandlerTest.java | 96 ++++++------ .../validation/data/Employee.java | 5 + .../validation/data/ValidateService.java | 12 +- .../validation/data/ValidationTestData.java | 42 +++++- 11 files changed, 262 insertions(+), 167 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java index f51beec04..c98d24a34 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java @@ -29,7 +29,7 @@ public class LocaleMessageInterpolator implements MessageInterpolator { /** * 构造函数,使用指定的目标消息插值器初始化实例。 * - * @param target 目标消息插值器 {@link MessageInterpolator}。 + * @param target 表示目标消息插值器的 {@link MessageInterpolator}。 */ public LocaleMessageInterpolator(MessageInterpolator target) { this.target = target; @@ -39,7 +39,7 @@ public LocaleMessageInterpolator(MessageInterpolator target) { /** * 构造函数,使用指定的地区初始化实例。 * - * @param locale 指定的地区 {@link Locale}。 + * @param locale 表示指定地区的 {@link Locale}。 */ public LocaleMessageInterpolator(Locale locale) { this.locale = locale; @@ -49,8 +49,8 @@ public LocaleMessageInterpolator(Locale locale) { /** * 构造函数,使用指定的目标消息插值器和地区初始化实例。 * - * @param target 被代理的目标消息插值器 {@link MessageInterpolator}。 - * @param locale 指示当前消息插值器要使用语言的相关地区 {@link Locale}。 + * @param target 表示被代理的目标消息插值器的 {@link MessageInterpolator}。 + * @param locale 表示当前消息插值器要使用语言的相关地区的 {@link Locale}。 */ public LocaleMessageInterpolator(MessageInterpolator target, Locale locale) { this.target = target; @@ -78,7 +78,7 @@ public String interpolate(String messageTemplate, Context context, Locale locale /** * 设置地区。 * - * @param locale 指示当前消息插值器要使用语言的相关地区 {@link Locale}。 + * @param locale 表示当前消息插值器要使用语言的相关地区的 {@link Locale}。 */ public void setLocale(Locale locale) { this.locale = locale; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 829419f02..ab4805c70 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -43,16 +43,16 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; - private LocaleMessageInterpolator messageInterpolator; + private final LocaleMessageInterpolator messageInterpolator; public ValidationHandler() { - messageInterpolator = new LocaleMessageInterpolator(); + this.messageInterpolator = new LocaleMessageInterpolator(); this.validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() - .messageInterpolator(messageInterpolator) + .messageInterpolator(this.messageInterpolator) .failFast(false) .buildValidatorFactory(); - this.validator = validatorFactory.getValidator(); + this.validator = this.validatorFactory.getValidator(); } /** @@ -122,21 +122,18 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { if (Arrays.stream(annotatedType.getAnnotations()).anyMatch(this::isJakartaConstraintAnnotation)) { return true; } - // 如果是参数化类型,递归检查类型参数。 - if (annotatedType instanceof AnnotatedParameterizedType) { - AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) annotatedType; + if (annotatedType instanceof AnnotatedParameterizedType parameterizedType) { return Arrays.stream(parameterizedType.getAnnotatedActualTypeArguments()) .anyMatch(this::hasConstraintAnnotationsInType); } - return false; } /** * 检查注解是否属于 {@code jakarta.validation} 注解。 *

- * 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + * 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: *

*
    *
  1. @@ -149,14 +146,15 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { *
* * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation}。 - * @return 如果属于 {@code jakarta.validation} 注解(即 @Valid 或携带 @Constraint),则返回 {@code true},否则返回 {@code false}。 + * @return 如果属于 {@code jakarta.validation} 注解(即 {@code @Valid} 或携带 {@code @Constraint}),则返回 {@code true},否则返回 + * {@code false}。 */ private boolean isJakartaConstraintAnnotation(Annotation annotation) { // @Valid 注解检查。 if ("jakarta.validation.Valid".equals(annotation.annotationType().getName())) { return true; } - // 检查 jakarta.validation.constraints, org.hibernate.validator.constraints 包下的注解或者用户根据 jakarta 标准自行实现的注解。 + // 检查 jakarta.validation.constraints,org.hibernate.validator.constraints 包下的注解或者用户根据 jakarta 标准自行实现的注解。 // 通过 Constraint 注解检查当前注解是否为校验注解。 Annotation[] metaAnnotations = annotation.annotationType().getAnnotations(); return Arrays.stream(metaAnnotations).anyMatch(metaAnnotation -> { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 9791b4566..377e0494a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -21,9 +21,9 @@ import modelengine.fitframework.util.ReflectionUtils; import modelengine.fitframework.validation.data.Company; import modelengine.fitframework.validation.data.Employee; -import modelengine.fitframework.validation.data.ValidationTestData; -import modelengine.fitframework.validation.data.ValidateService; import modelengine.fitframework.validation.data.GroupValidateService; +import modelengine.fitframework.validation.data.ValidateService; +import modelengine.fitframework.validation.data.ValidationTestData; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -58,10 +58,10 @@ public class ValidationHandlerTest { @BeforeEach void setUp() { - handler.setLocale(Locale.CHINA); - when(validated.value()).thenReturn(new Class[0]); - when(fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); - when(beanContainer.runtime()).thenReturn(fitRuntime); + this.handler.setLocale(Locale.CHINA); + when(this.validated.value()).thenReturn(new Class[0]); + when(this.fitRuntime.resolverOfAnnotations()).thenReturn(this.annotationMetadataResolver); + when(this.beanContainer.runtime()).thenReturn(this.fitRuntime); } private ConstraintViolationException invokeHandleMethod(Method targetMethod, Object[] args) { @@ -71,10 +71,10 @@ private ConstraintViolationException invokeHandleMethod(Method targetMethod, Obj JoinPoint joinPoint = mock(JoinPoint.class); when(joinPoint.getMethod()).thenReturn(targetMethod); when(joinPoint.getArgs()).thenReturn(args); - when(joinPoint.getTarget()).thenReturn(validateService); + when(joinPoint.getTarget()).thenReturn(this.validateService); InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + () -> handleValidatedMethod.invoke(this.handler, joinPoint, this.validated)); return ObjectUtils.cast(invocationTargetException.getTargetException()); } @@ -107,7 +107,7 @@ void giveNestedClassThenValidateOk() { } @Test - @DisplayName("测试@NotNull注解") + @DisplayName("测试 @NotNull 注解") void testNotNullValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNotNull", String.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {null}); @@ -115,7 +115,7 @@ void testNotNullValidation() { } @Test - @DisplayName("测试@NotEmpty注解") + @DisplayName("测试 @NotEmpty 注解") void testNotEmptyValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNotEmpty", String.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {""}); @@ -123,7 +123,7 @@ void testNotEmptyValidation() { } @Test - @DisplayName("测试@NotBlank注解") + @DisplayName("测试 @NotBlank 注解") void testNotBlankValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNotBlank", String.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {" "}); @@ -131,7 +131,7 @@ void testNotBlankValidation() { } @Test - @DisplayName("测试@Null注解") + @DisplayName("测试 @Null 注解") void testNullValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNull", String.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"not null"}); @@ -139,7 +139,7 @@ void testNullValidation() { } @Test - @DisplayName("测试@Size注解-字符串") + @DisplayName("测试 @Size 注解 - 字符串") void testSizeStringValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testSize", String.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"a"}); @@ -147,7 +147,7 @@ void testSizeStringValidation() { } @Test - @DisplayName("测试@Size注解-集合") + @DisplayName("测试 @Size 注解 - 集合") void testSizeListValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testSizeList", List.class); ConstraintViolationException exception = @@ -156,7 +156,7 @@ void testSizeListValidation() { } @Test - @DisplayName("测试@Min注解") + @DisplayName("测试 @Min 注解") void testMinValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testMin", int.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {5}); @@ -164,7 +164,7 @@ void testMinValidation() { } @Test - @DisplayName("测试@Max注解") + @DisplayName("测试 @Max 注解") void testMaxValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testMax", int.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {150}); @@ -172,7 +172,7 @@ void testMaxValidation() { } @Test - @DisplayName("测试@DecimalMin注解") + @DisplayName("测试 @DecimalMin 注解") void testDecimalMinValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testDecimalMin", BigDecimal.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("5.0")}); @@ -180,7 +180,7 @@ void testDecimalMinValidation() { } @Test - @DisplayName("测试@DecimalMax注解") + @DisplayName("测试 @DecimalMax 注解") void testDecimalMaxValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testDecimalMax", BigDecimal.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("150.0")}); @@ -188,7 +188,7 @@ void testDecimalMaxValidation() { } @Test - @DisplayName("测试@Positive注解") + @DisplayName("测试 @Positive 注解") void testPositiveValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPositive", int.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {0}); @@ -196,7 +196,7 @@ void testPositiveValidation() { } @Test - @DisplayName("测试@PositiveOrZero注解") + @DisplayName("测试 @PositiveOrZero 注解") void testPositiveOrZeroValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPositiveOrZero", int.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {-1}); @@ -204,7 +204,7 @@ void testPositiveOrZeroValidation() { } @Test - @DisplayName("测试@Negative注解") + @DisplayName("测试 @Negative 注解") void testNegativeValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNegative", int.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {1}); @@ -212,7 +212,7 @@ void testNegativeValidation() { } @Test - @DisplayName("测试@NegativeOrZero注解") + @DisplayName("测试 @NegativeOrZero 注解") void testNegativeOrZeroValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNegativeOrZero", int.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {1}); @@ -220,7 +220,7 @@ void testNegativeOrZeroValidation() { } @Test - @DisplayName("测试@Digits注解") + @DisplayName("测试 @Digits 注解") void testDigitsValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testDigits", BigDecimal.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("1234.567")}); @@ -228,7 +228,7 @@ void testDigitsValidation() { } @Test - @DisplayName("测试@Past注解") + @DisplayName("测试 @Past 注解") void testPastValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPast", LocalDate.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {LocalDate.now().plusDays(1)}); @@ -236,7 +236,7 @@ void testPastValidation() { } @Test - @DisplayName("测试@PastOrPresent注解") + @DisplayName("测试 @PastOrPresent 注解") void testPastOrPresentValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPastOrPresent", LocalDate.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {LocalDate.now().plusDays(1)}); @@ -244,7 +244,7 @@ void testPastOrPresentValidation() { } @Test - @DisplayName("测试@Future注解") + @DisplayName("测试 @Future 注解") void testFutureValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testFuture", LocalDate.class); ConstraintViolationException exception = @@ -253,7 +253,7 @@ void testFutureValidation() { } @Test - @DisplayName("测试@FutureOrPresent注解") + @DisplayName("测试 @FutureOrPresent 注解") void testFutureOrPresentValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testFutureOrPresent", LocalDate.class); @@ -263,7 +263,7 @@ void testFutureOrPresentValidation() { } @Test - @DisplayName("测试@Pattern注解") + @DisplayName("测试 @Pattern 注解") void testPatternValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testPattern", String.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"123"}); @@ -271,7 +271,7 @@ void testPatternValidation() { } @Test - @DisplayName("测试@Email注解") + @DisplayName("测试 @Email 注解") void testEmailValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testEmail", String.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"invalid-email"}); @@ -279,7 +279,7 @@ void testEmailValidation() { } @Test - @DisplayName("测试@AssertTrue注解") + @DisplayName("测试 @AssertTrue 注解") void testAssertTrueValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testAssertTrue", boolean.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {false}); @@ -287,7 +287,7 @@ void testAssertTrueValidation() { } @Test - @DisplayName("测试@AssertFalse注解") + @DisplayName("测试 @AssertFalse 注解") void testAssertFalseValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testAssertFalse", boolean.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {true}); @@ -381,10 +381,14 @@ public void givenParametersThenTeacherGroupValidateNotHappened() { when(joinPoint.getMethod()).thenReturn(method); when(joinPoint.getArgs()).thenReturn(new Object[] {15}); when(joinPoint.getTarget()).thenReturn(new GroupValidateService.TeacherValidateService()); - when(validated.value()).thenReturn(new Class[] {ValidationTestData.TeacherGroup.class}); + when(ValidationHandlerTest.this.validated.value()).thenReturn(new Class[] { + ValidationTestData.TeacherGroup.class + }); InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + () -> handleValidatedMethod.invoke(ValidationHandlerTest.this.handler, + joinPoint, + ValidationHandlerTest.this.validated)); ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); assertThat(exception.getMessage()).contains("范围要在22~65之内"); @@ -415,10 +419,14 @@ void testValidateAdvancedGroup() { when(joinPoint.getArgs()).thenReturn(new Object[] {data}); when(joinPoint.getTarget()).thenReturn(new GroupValidateService.AdvancedValidateService()); - when(validated.value()).thenReturn(new Class[] {ValidationTestData.AdvancedGroup.class}); + when(ValidationHandlerTest.this.validated.value()).thenReturn(new Class[] { + ValidationTestData.AdvancedGroup.class + }); InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + () -> handleValidatedMethod.invoke(ValidationHandlerTest.this.handler, + joinPoint, + ValidationHandlerTest.this.validated)); ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); assertThat(exception.getMessage()).contains("高级组年龄必须小于等于200"); @@ -575,7 +583,7 @@ void shouldReturnMsgWhenValidateListInMap() { invalidData.setAge(-1); List dataList1 = Arrays.asList(validData, invalidData); - List dataList2 = Arrays.asList(validData); + List dataList2 = List.of(validData); Map> map = new HashMap<>(); map.put(validEmployee, dataList1); @@ -590,65 +598,65 @@ void shouldReturnMsgWhenValidateListInMap() { void shouldReturnMsgWhenValidateListComplex() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateCompanyList", List.class); Employee invalidEmployee = new Employee("", 17); - Company invalidCompany = new Company(Arrays.asList(invalidEmployee)); - List companies = Arrays.asList(invalidCompany); + Company invalidCompany = new Company(List.of(invalidEmployee)); + List companies = List.of(invalidCompany); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {companies}); assertThat(exception).isNotNull(); } @Test - @DisplayName("测试@NotNull注解-成功场景") + @DisplayName("测试 @NotNull 注解 - 成功场景") void testNotNullValidationSuccess() { - validateService.testNotNull("valid value"); + this.validateService.testNotNull("valid value"); } @Test - @DisplayName("测试@Size注解-最小边界值") + @DisplayName("测试 @Size 注解 - 最小边界值") void testSizeStringValidationMinBoundary() { - validateService.testSize("ab"); // 2个字符,最小边界 + this.validateService.testSize("ab"); // 2个字符,最小边界 } @Test - @DisplayName("测试@Size注解-最大边界值") + @DisplayName("测试 @Size 注解 - 最大边界值") void testSizeStringValidationMaxBoundary() { - validateService.testSize("abcdefghij"); // 10个字符,最大边界 + this.validateService.testSize("abcdefghij"); // 10个字符,最大边界 } @Test - @DisplayName("测试@Min注解-边界值") + @DisplayName("测试 @Min 注解 - 边界值") void testMinValidationBoundary() { - validateService.testMin(10); // 最小值边界 + this.validateService.testMin(10); // 最小值边界 } @Test - @DisplayName("测试@Max注解-边界值") + @DisplayName("测试 @Max 注解 - 边界值") void testMaxValidationBoundary() { - validateService.testMax(100); // 最大值边界 + this.validateService.testMax(100); // 最大值边界 } @Test - @DisplayName("测试@Positive注解-边界值") + @DisplayName("测试 @Positive 注解 - 边界值") void testPositiveValidationBoundary() { - validateService.testPositive(1); // 最小正数 + this.validateService.testPositive(1); // 最小正数 } @Test - @DisplayName("测试@PositiveOrZero注解-零值") + @DisplayName("测试 @PositiveOrZero 注解 - 零值") void testPositiveOrZeroValidationZero() { - validateService.testPositiveOrZero(0); // 零值 + this.validateService.testPositiveOrZero(0); // 零值 } @Test - @DisplayName("测试@Past注解-边界值") + @DisplayName("测试 @Past 注解 - 边界值") void testPastValidationBoundary() { - validateService.testPast(LocalDate.now().minusDays(1)); // 昨天 + this.validateService.testPast(LocalDate.now().minusDays(1)); // 昨天 } @Test - @DisplayName("测试@Future注解-边界值") + @DisplayName("测试 @Future 注解 - 边界值") void testFutureValidationBoundary() { - validateService.testFuture(LocalDate.now().plusDays(1)); // 明天 + this.validateService.testFuture(LocalDate.now().plusDays(1)); // 明天 } @Test @@ -663,7 +671,7 @@ void testValidComplexObject() { validData.setDiscount(new BigDecimal("-5.0")); validData.setAgreed(true); - validateService.testValidObject(validData); + this.validateService.testValidObject(validData); } @Test @@ -691,7 +699,7 @@ void testMixedPrimitiveAndObjectValidation() { } @Test - @DisplayName("测试空集合和null值混合") + @DisplayName("测试空集合和 null 值混合") void testEmptyCollectionAndNullMixed() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateMixedCollections", @@ -703,7 +711,7 @@ void testEmptyCollectionAndNullMixed() { } @Test - @DisplayName("测试@Range注解-最小值验证") + @DisplayName("测试 @Range 注解 - 最小值验证") void testRangeMinValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRange", int.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {5}); @@ -711,7 +719,7 @@ void testRangeMinValidation() { } @Test - @DisplayName("测试@Range注解-最大值验证") + @DisplayName("测试 @Range 注解 - 最大值验证") void testRangeMaxValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRange", int.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {150}); @@ -719,25 +727,25 @@ void testRangeMaxValidation() { } @Test - @DisplayName("测试@Range注解-最小边界值") + @DisplayName("测试 @Range 注解 - 最小边界值") void testRangeMinBoundary() { - validateService.testRange(10); // 最小边界值,应该通过 + this.validateService.testRange(10); // 最小边界值,应该通过 } @Test - @DisplayName("测试@Range注解-最大边界值") + @DisplayName("测试 @Range 注解 - 最大边界值") void testRangeMaxBoundary() { - validateService.testRange(100); // 最大边界值,应该通过 + this.validateService.testRange(100); // 最大边界值,应该通过 } @Test - @DisplayName("测试@Range注解-中间值") + @DisplayName("测试 @Range 注解 - 中间值") void testRangeValidValue() { - validateService.testRange(50); // 中间值,应该通过 + this.validateService.testRange(50); // 中间值,应该通过 } @Test - @DisplayName("测试@Range注解-BigDecimal类型") + @DisplayName("测试 @Range 注解 - BigDecimal 类型") void testRangeBigDecimalValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRangeBigDecimal", BigDecimal.class); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java index d5775b2a9..892f9a994 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -39,7 +39,12 @@ public Employee(String name, int age) { this.age = age; } + /** + * 获取员工姓名。 + * + * @return 表示员工姓名的 {@link String}。 + */ public String getName() { - return name; + return this.name; } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index 0d7e3f0f8..49a72914b 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -52,36 +52,70 @@ public interface TeacherGroup {} @AssertTrue(message = "必须同意条款") private Boolean agreed; + /** + * 构造函数。 + */ public ValidationTestData() {} - public String getName() { - return name; - } - + /** + * 设置名称。 + * + * @param name 表示名称的 {@link String}。 + */ public void setName(String name) { this.name = name; } + /** + * 设置年龄。 + * + * @param age 表示年龄的 {@link Integer}。 + */ public void setAge(Integer age) { this.age = age; } + /** + * 设置描述。 + * + * @param description 表示描述的 {@link String}。 + */ public void setDescription(String description) { this.description = description; } + /** + * 设置内容。 + * + * @param content 表示内容的 {@link String}。 + */ public void setContent(String content) { this.content = content; } + /** + * 设置数量。 + * + * @param quantity 表示数量的 {@link Integer}。 + */ public void setQuantity(Integer quantity) { this.quantity = quantity; } + /** + * 设置折扣。 + * + * @param discount 表示折扣的 {@link BigDecimal}。 + */ public void setDiscount(BigDecimal discount) { this.discount = discount; } + /** + * 设置是否同意条款。 + * + * @param agreed 表示是否同意条款的 {@link Boolean}。 + */ public void setAgreed(Boolean agreed) { this.agreed = agreed; } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java index 816e3c5d2..1af7a0d87 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java @@ -6,12 +6,12 @@ package modelengine.fitframework.validation; -import javax.validation.MessageInterpolator; - import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import java.util.Locale; +import javax.validation.MessageInterpolator; + /** * 地区消息插值器。 *

@@ -29,7 +29,7 @@ public class LocaleMessageInterpolator implements MessageInterpolator { /** * 构造函数,使用指定的目标消息插值器初始化实例。 * - * @param target 目标消息插值器 {@link MessageInterpolator}。 + * @param target 表示目标消息插值器的 {@link MessageInterpolator}。 */ public LocaleMessageInterpolator(MessageInterpolator target) { this.target = target; @@ -39,7 +39,7 @@ public LocaleMessageInterpolator(MessageInterpolator target) { /** * 构造函数,使用指定的地区初始化实例。 * - * @param locale 指定的地区 {@link Locale}。 + * @param locale 表示指定地区的 {@link Locale}。 */ public LocaleMessageInterpolator(Locale locale) { this.locale = locale; @@ -49,8 +49,8 @@ public LocaleMessageInterpolator(Locale locale) { /** * 构造函数,使用指定的目标消息插值器和地区初始化实例。 * - * @param target 被代理的目标消息插值器 {@link MessageInterpolator}。 - * @param locale 指示当前消息插值器要使用语言的相关地区 {@link Locale}。 + * @param target 表示被代理的目标消息插值器的 {@link MessageInterpolator}。 + * @param locale 表示当前消息插值器要使用语言的相关地区的 {@link Locale}。 */ public LocaleMessageInterpolator(MessageInterpolator target, Locale locale) { this.target = target; @@ -67,18 +67,18 @@ public LocaleMessageInterpolator() { @Override public String interpolate(String messageTemplate, Context context) { - return target.interpolate(messageTemplate, context, this.locale); + return this.target.interpolate(messageTemplate, context, this.locale); } @Override public String interpolate(String messageTemplate, Context context, Locale locale) { - return target.interpolate(messageTemplate, context, this.locale); + return this.target.interpolate(messageTemplate, context, this.locale); } /** * 设置地区。 * - * @param locale 指示当前消息插值器要使用语言的相关地区 {@link Locale}。 + * @param locale 表示当前消息插值器要使用语言的相关地区的 {@link Locale}。 */ public void setLocale(Locale locale) { this.locale = locale; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 199956f32..40e9086df 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -6,12 +6,6 @@ package modelengine.fitframework.validation; -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; -import javax.validation.executable.ExecutableValidator; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Scope; import modelengine.fitframework.aop.JoinPoint; @@ -29,6 +23,13 @@ import java.util.Locale; import java.util.Set; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import javax.validation.executable.ExecutableValidator; + /** * 校验入口类。 *

@@ -43,22 +44,22 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; - private LocaleMessageInterpolator messageInterpolator; + private final LocaleMessageInterpolator messageInterpolator; public ValidationHandler() { this.messageInterpolator = new LocaleMessageInterpolator(); this.validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() - .messageInterpolator(messageInterpolator) + .messageInterpolator(this.messageInterpolator) .failFast(false) .buildValidatorFactory(); - this.validator = validatorFactory.getValidator(); + this.validator = this.validatorFactory.getValidator(); } /** * 设置校验信息语言。 * - * @param locale 校验语言 {@link Locale}。 + * @param locale 表示校验语言的 {@link Locale}。 */ public void setLocale(Locale locale) { this.messageInterpolator.setLocale(locale); @@ -67,8 +68,8 @@ public void setLocale(Locale locale) { /** * 方法参数校验处理。 * - * @param joinPoint 表示切面的切点 {@link JoinPoint}。 - * @param validated 切点方法所属类的校验注解 {@link Validated}。 + * @param joinPoint 表示切面切点的 {@link JoinPoint}。 + * @param validated 表示切点方法所属类的校验注解的 {@link Validated}。 */ @Before(value = "@target(validated) && execution(public * *(..))", argNames = "joinPoint, validated") private void handle(JoinPoint joinPoint, Validated validated) { @@ -122,21 +123,18 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { if (annotatedType.getAnnotations().length > 0) { return Arrays.stream(annotatedType.getAnnotations()).anyMatch(this::isJavaxConstraintAnnotation); } - // 如果是参数化类型,递归检查类型参数。 - if (annotatedType instanceof AnnotatedParameterizedType) { - AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) annotatedType; + if (annotatedType instanceof AnnotatedParameterizedType parameterizedType) { return Arrays.stream(parameterizedType.getAnnotatedActualTypeArguments()) .anyMatch(this::hasConstraintAnnotationsInType); } - return false; } /** * 检查注解是否属于 {@code javax.validation} 注解。 *

- * 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: + * 由于存在嵌套校验的情况,{@code @Valid} 与其他校验注解都可以标注参数需要进行校验,但两者的实现与语义上存在差异,处理逻辑不能合并,因此分情况讨论: *

*
    *
  1. @@ -149,7 +147,8 @@ private boolean hasConstraintAnnotationsInType(AnnotatedType annotatedType) { *
* * @param annotation 要检查的注解 {@link java.lang.annotation.Annotation}。 - * @return 如果属于 {@code javax.validation} 注解(即 @Valid 或携带 @Constraint),则返回 {@code true},否则返回 {@code false}。 + * @return 如果属于 {@code javax.validation} 注解(即 {@code @Valid} 或携带 {@code @Constraint}),则返回 {@code true},否则返回 + * {@code false}。 */ private boolean isJavaxConstraintAnnotation(Annotation annotation) { // @Valid 注解检查。 diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index cb97d97c9..b23b8dd09 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -11,8 +11,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import javax.validation.ConstraintViolationException; - import modelengine.fitframework.aop.JoinPoint; import modelengine.fitframework.ioc.BeanContainer; import modelengine.fitframework.ioc.annotation.AnnotationMetadataResolver; @@ -22,9 +20,9 @@ import modelengine.fitframework.util.ReflectionUtils; import modelengine.fitframework.validation.data.Company; import modelengine.fitframework.validation.data.Employee; -import modelengine.fitframework.validation.data.ValidationTestData; -import modelengine.fitframework.validation.data.ValidateService; import modelengine.fitframework.validation.data.GroupValidateService; +import modelengine.fitframework.validation.data.ValidateService; +import modelengine.fitframework.validation.data.ValidationTestData; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -43,6 +41,8 @@ import java.util.Locale; import java.util.Map; +import javax.validation.ConstraintViolationException; + /** * {@link ValidationHandler} 的单元测试。 * @@ -353,10 +353,14 @@ public void givenParametersThenGroupValidateHappened() { when(joinPoint.getMethod()).thenReturn(method); when(joinPoint.getArgs()).thenReturn(new Object[] {25}); when(joinPoint.getTarget()).thenReturn(new GroupValidateService.StudentValidateService()); - when(validated.value()).thenReturn(new Class[] {ValidationTestData.StudentGroup.class}); + when(ValidationHandlerTest.this.validated.value()).thenReturn(new Class[] { + ValidationTestData.StudentGroup.class + }); InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + () -> handleValidatedMethod.invoke(ValidationHandlerTest.this.handler, + joinPoint, + ValidationHandlerTest.this.validated)); ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); assertThat(exception.getMessage()).contains("范围要在7~20之内"); @@ -382,10 +386,14 @@ public void givenParametersThenTeacherGroupValidateNotHappened() { when(joinPoint.getMethod()).thenReturn(method); when(joinPoint.getArgs()).thenReturn(new Object[] {15}); when(joinPoint.getTarget()).thenReturn(new GroupValidateService.TeacherValidateService()); - when(validated.value()).thenReturn(new Class[] {ValidationTestData.TeacherGroup.class}); + when(ValidationHandlerTest.this.validated.value()).thenReturn(new Class[] { + ValidationTestData.TeacherGroup.class + }); InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + () -> handleValidatedMethod.invoke(ValidationHandlerTest.this.handler, + joinPoint, + ValidationHandlerTest.this.validated)); ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); assertThat(exception.getMessage()).contains("范围要在22~65之内"); @@ -416,10 +424,14 @@ void testValidateAdvancedGroup() { when(joinPoint.getArgs()).thenReturn(new Object[] {data}); when(joinPoint.getTarget()).thenReturn(new GroupValidateService.AdvancedValidateService()); - when(validated.value()).thenReturn(new Class[] {ValidationTestData.AdvancedGroup.class}); + when(ValidationHandlerTest.this.validated.value()).thenReturn(new Class[] { + ValidationTestData.AdvancedGroup.class + }); InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + () -> handleValidatedMethod.invoke(ValidationHandlerTest.this.handler, + joinPoint, + ValidationHandlerTest.this.validated)); ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); assertThat(exception.getMessage()).contains("高级组年龄必须小于等于200"); @@ -576,7 +588,7 @@ void shouldReturnMsgWhenValidateListInMap() { invalidData.setAge(-1); List dataList1 = Arrays.asList(validData, invalidData); - List dataList2 = Arrays.asList(validData); + List dataList2 = List.of(validData); Map> map = new HashMap<>(); map.put(validEmployee, dataList1); @@ -591,65 +603,65 @@ void shouldReturnMsgWhenValidateListInMap() { void shouldReturnMsgWhenValidateListComplex() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateCompanyList", List.class); Employee invalidEmployee = new Employee("", 17); - Company invalidCompany = new Company(Arrays.asList(invalidEmployee)); - List companies = Arrays.asList(invalidCompany); + Company invalidCompany = new Company(List.of(invalidEmployee)); + List companies = List.of(invalidCompany); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {companies}); assertThat(exception).isNotNull(); } @Test - @DisplayName("测试@NotNull注解-成功场景") + @DisplayName("测试 @NotNull 注解 - 成功场景") void testNotNullValidationSuccess() { - validateService.testNotNull("valid value"); + this.validateService.testNotNull("valid value"); } @Test - @DisplayName("测试@Size注解-最小边界值") + @DisplayName("测试 @Size 注解 - 最小边界值") void testSizeStringValidationMinBoundary() { - validateService.testSize("ab"); // 2个字符,最小边界 + this.validateService.testSize("ab"); // 2个字符,最小边界 } @Test - @DisplayName("测试@Size注解-最大边界值") + @DisplayName("测试 @Size 注解 - 最大边界值") void testSizeStringValidationMaxBoundary() { - validateService.testSize("abcdefghij"); // 10个字符,最大边界 + this.validateService.testSize("abcdefghij"); // 10个字符,最大边界 } @Test - @DisplayName("测试@Min注解-边界值") + @DisplayName("测试 @Min 注解 - 边界值") void testMinValidationBoundary() { - validateService.testMin(10); // 最小值边界 + this.validateService.testMin(10); // 最小值边界 } @Test - @DisplayName("测试@Max注解-边界值") + @DisplayName("测试 @Max 注解 - 边界值") void testMaxValidationBoundary() { - validateService.testMax(100); // 最大值边界 + this.validateService.testMax(100); // 最大值边界 } @Test - @DisplayName("测试@Positive注解-边界值") + @DisplayName("测试 @Positive 注解 - 边界值") void testPositiveValidationBoundary() { - validateService.testPositive(1); // 最小正数 + this.validateService.testPositive(1); // 最小正数 } @Test - @DisplayName("测试@PositiveOrZero注解-零值") + @DisplayName("测试 @PositiveOrZero 注解 - 零值") void testPositiveOrZeroValidationZero() { - validateService.testPositiveOrZero(0); // 零值 + this.validateService.testPositiveOrZero(0); // 零值 } @Test - @DisplayName("测试@Past注解-边界值") + @DisplayName("测试 @Past 注解 - 边界值") void testPastValidationBoundary() { - validateService.testPast(LocalDate.now().minusDays(1)); // 昨天 + this.validateService.testPast(LocalDate.now().minusDays(1)); // 昨天 } @Test - @DisplayName("测试@Future注解-边界值") + @DisplayName("测试 @Future 注解 - 边界值") void testFutureValidationBoundary() { - validateService.testFuture(LocalDate.now().plusDays(1)); // 明天 + this.validateService.testFuture(LocalDate.now().plusDays(1)); // 明天 } @Test @@ -664,7 +676,7 @@ void testValidComplexObject() { validData.setDiscount(new BigDecimal("-5.0")); validData.setAgreed(true); - validateService.testValidObject(validData); + this.validateService.testValidObject(validData); } @Test @@ -692,7 +704,7 @@ void testMixedPrimitiveAndObjectValidation() { } @Test - @DisplayName("测试空集合和null值混合") + @DisplayName("测试空集合和 null 值混合") void testEmptyCollectionAndNullMixed() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "validateMixedCollections", @@ -704,7 +716,7 @@ void testEmptyCollectionAndNullMixed() { } @Test - @DisplayName("测试@Range注解-最小值验证") + @DisplayName("测试 @Range 注解 - 最小值验证") void testRangeMinValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRange", int.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {5}); @@ -712,7 +724,7 @@ void testRangeMinValidation() { } @Test - @DisplayName("测试@Range注解-最大值验证") + @DisplayName("测试 @Range 注解 - 最大值验证") void testRangeMaxValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRange", int.class); ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {150}); @@ -720,25 +732,25 @@ void testRangeMaxValidation() { } @Test - @DisplayName("测试@Range注解-最小边界值") + @DisplayName("测试 @Range 注解 - 最小边界值") void testRangeMinBoundary() { - validateService.testRange(10); // 最小边界值,应该通过 + this.validateService.testRange(10); // 最小边界值,应该通过 } @Test - @DisplayName("测试@Range注解-最大边界值") + @DisplayName("测试 @Range 注解 - 最大边界值") void testRangeMaxBoundary() { - validateService.testRange(100); // 最大边界值,应该通过 + this.validateService.testRange(100); // 最大边界值,应该通过 } @Test - @DisplayName("测试@Range注解-中间值") + @DisplayName("测试 @Range 注解 - 中间值") void testRangeValidValue() { - validateService.testRange(50); // 中间值,应该通过 + this.validateService.testRange(50); // 中间值,应该通过 } @Test - @DisplayName("测试@Range注解-BigDecimal类型") + @DisplayName("测试 @Range 注解 - BigDecimal 类型") void testRangeBigDecimalValidation() { Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testRangeBigDecimal", BigDecimal.class); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java index cd0db61b1..a46b161bf 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -39,6 +39,11 @@ public Employee(String name, int age) { this.age = age; } + /** + * 获取员工姓名。 + * + * @return 返回员工姓名的 {@link String}。 + */ public String getName() { return name; } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index b8704becf..56c837133 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -305,8 +305,8 @@ public void validateNameAndAge(@NotBlank String name, @Positive int age) { * @param data 表示输入的 {@link ValidationTestData}。 */ public void validateAdvancedGroup(ValidationTestData data) { - if (advancedValidateService != null) { - advancedValidateService.validateAdvancedGroup(data); + if (this.advancedValidateService != null) { + this.advancedValidateService.validateAdvancedGroup(data); } } @@ -316,8 +316,8 @@ public void validateAdvancedGroup(ValidationTestData data) { * @param age 表示输入的 {@code int}。 */ public void validateStudentAge(int age) { - if (studentValidateService != null) { - studentValidateService.validateStudentAge(age); + if (this.studentValidateService != null) { + this.studentValidateService.validateStudentAge(age); } } @@ -327,8 +327,8 @@ public void validateStudentAge(int age) { * @param age 表示输入的 {@code int}。 */ public void validateTeacherAge(int age) { - if (teacherValidateService != null) { - teacherValidateService.validateTeacherAge(age); + if (this.teacherValidateService != null) { + this.teacherValidateService.validateTeacherAge(age); } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java index 2341d2501..59234a991 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/ValidationTestData.java @@ -52,36 +52,70 @@ public interface TeacherGroup {} @AssertTrue(message = "必须同意条款") private Boolean agreed; + /** + * 构造函数。 + */ public ValidationTestData() {} - public String getName() { - return name; - } - + /** + * 设置名称。 + * + * @param name 表示名称的 {@link String}。 + */ public void setName(String name) { this.name = name; } + /** + * 设置年龄。 + * + * @param age 表示年龄的 {@link Integer}。 + */ public void setAge(Integer age) { this.age = age; } + /** + * 设置描述。 + * + * @param description 表示描述的 {@link String}。 + */ public void setDescription(String description) { this.description = description; } + /** + * 设置内容。 + * + * @param content 表示内容的 {@link String}。 + */ public void setContent(String content) { this.content = content; } + /** + * 设置数量。 + * + * @param quantity 表示数量的 {@link Integer}。 + */ public void setQuantity(Integer quantity) { this.quantity = quantity; } + /** + * 设置折扣。 + * + * @param discount 表示折扣的 {@link BigDecimal}。 + */ public void setDiscount(BigDecimal discount) { this.discount = discount; } + /** + * 确认是否同意。 + * + * @param agreed 表示是否同意的 {@link Boolean}。 + */ public void setAgreed(Boolean agreed) { this.agreed = agreed; } From c9f4387c5c13cc67321e0b2a8825d5ca87f04942 Mon Sep 17 00:00:00 2001 From: jiyujie Date: Tue, 19 Aug 2025 21:26:49 +0800 Subject: [PATCH 21/23] Add dependency --- framework/dependency/pom.xml | 27 ++++++++++++-------- framework/fit/java/jacoco-aggregator/pom.xml | 18 +++++++++---- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/framework/dependency/pom.xml b/framework/dependency/pom.xml index ed91e09d7..d9d50fb79 100644 --- a/framework/dependency/pom.xml +++ b/framework/dependency/pom.xml @@ -203,16 +203,6 @@ fit-transaction ${fit.version}
- - org.fitframework.extension - fit-validation - ${fit.version} - - - org.fitframework.extension - fit-validation-hibernate - ${fit.version} - @@ -360,11 +350,21 @@ fit-service-coordination-locator ${fit.version} + + org.fitframework.plugin + fit-service-coordination-nacos + ${fit.version} + org.fitframework.plugin fit-service-coordination-simple ${fit.version} + + org.fitframework.plugin + fit-service-discovery + ${fit.version} + org.fitframework.plugin fit-service-registry @@ -372,7 +372,12 @@ org.fitframework.plugin - fit-service-discovery + fit-validation-hibernate-jakarta + ${fit.version} + + + org.fitframework.plugin + fit-validation-hibernate-javax ${fit.version} diff --git a/framework/fit/java/jacoco-aggregator/pom.xml b/framework/fit/java/jacoco-aggregator/pom.xml index 24357f0d2..42d0f62b6 100644 --- a/framework/fit/java/jacoco-aggregator/pom.xml +++ b/framework/fit/java/jacoco-aggregator/pom.xml @@ -98,10 +98,6 @@ org.fitframework.extension fit-transaction - - org.fitframework.extension - fit-validation - @@ -196,17 +192,29 @@ org.fitframework.plugin fit-service-coordination-locator + + org.fitframework.plugin + fit-service-coordination-nacos + org.fitframework.plugin fit-service-coordination-simple + + org.fitframework.plugin + fit-service-discovery + org.fitframework.plugin fit-service-registry org.fitframework.plugin - fit-service-discovery + fit-validation-hibernate-jakarta + + + org.fitframework.plugin + fit-validation-hibernate-javax org.fitframework.plugin From 6d6652dca1fd10cded2419ef5ca6e13e7ed5a89c Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Tue, 19 Aug 2025 21:57:46 +0800 Subject: [PATCH 22/23] =?UTF-8?q?[fit]=20=E4=BF=AE=E6=94=B9=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=8F=92=E5=80=BC=E5=99=A8=E4=BB=A3=E7=90=86=E4=B8=AD?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=9A=84locale=E8=AE=BE=E7=BD=AE=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fitframework/validation/LocaleMessageInterpolator.java | 2 +- .../fitframework/validation/LocaleMessageInterpolator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java index c98d24a34..f339d6342 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java @@ -72,7 +72,7 @@ public String interpolate(String messageTemplate, Context context) { @Override public String interpolate(String messageTemplate, Context context, Locale locale) { - return target.interpolate(messageTemplate, context, this.locale); + return target.interpolate(messageTemplate, context, locale); } /** diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java index 1af7a0d87..74438d75c 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java @@ -72,7 +72,7 @@ public String interpolate(String messageTemplate, Context context) { @Override public String interpolate(String messageTemplate, Context context, Locale locale) { - return this.target.interpolate(messageTemplate, context, this.locale); + return this.target.interpolate(messageTemplate, context, locale); } /** From 8dca97df5aa054b358b56cc2968d7d5a91fe223b Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Wed, 20 Aug 2025 10:04:58 +0800 Subject: [PATCH 23/23] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/LocaleMessageInterpolator.java | 4 ++-- .../validation/ValidationHandlerTest.java | 11 +++++++---- .../validation/data/ValidateService.java | 12 ++++++------ .../fitframework/validation/data/Employee.java | 2 +- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java index f339d6342..fc22cc98a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java @@ -67,12 +67,12 @@ public LocaleMessageInterpolator() { @Override public String interpolate(String messageTemplate, Context context) { - return target.interpolate(messageTemplate, context, this.locale); + return this.target.interpolate(messageTemplate, context, this.locale); } @Override public String interpolate(String messageTemplate, Context context, Locale locale) { - return target.interpolate(messageTemplate, context, locale); + return this.target.interpolate(messageTemplate, context, locale); } /** diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 377e0494a..2b5d9def0 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -341,8 +341,7 @@ class StudentGroupValidationTests { public void givenParametersThenGroupValidateHappened() { // 测试学生年龄验证 - 现在会抛出异常,因为使用了学生分组 Method method = ReflectionUtils.getDeclaredMethod(GroupValidateService.StudentValidateService.class, - "validateStudentAge", - int.class); + "validateStudentAge", int.class); Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, "handle", JoinPoint.class, @@ -352,10 +351,14 @@ public void givenParametersThenGroupValidateHappened() { when(joinPoint.getMethod()).thenReturn(method); when(joinPoint.getArgs()).thenReturn(new Object[] {25}); when(joinPoint.getTarget()).thenReturn(new GroupValidateService.StudentValidateService()); - when(validated.value()).thenReturn(new Class[] {ValidationTestData.StudentGroup.class}); + when(ValidationHandlerTest.this.validated.value()).thenReturn(new Class[] { + ValidationTestData.StudentGroup.class + }); InvocationTargetException invocationTargetException = catchThrowableOfType(InvocationTargetException.class, - () -> handleValidatedMethod.invoke(handler, joinPoint, validated)); + () -> handleValidatedMethod.invoke(ValidationHandlerTest.this.handler, + joinPoint, + ValidationHandlerTest.this.validated)); ConstraintViolationException exception = ObjectUtils.cast(invocationTargetException.getTargetException()); assertThat(exception.getMessage()).contains("范围要在7~20之内"); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java index 075146232..89ace7ae5 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/ValidateService.java @@ -304,8 +304,8 @@ public void validateNameAndAge(@NotBlank String name, @Positive int age) { * @param data 表示输入的 {@link ValidationTestData}。 */ public void validateAdvancedGroup(ValidationTestData data) { - if (advancedValidateService != null) { - advancedValidateService.validateAdvancedGroup(data); + if (this.advancedValidateService != null) { + this.advancedValidateService.validateAdvancedGroup(data); } } @@ -315,8 +315,8 @@ public void validateAdvancedGroup(ValidationTestData data) { * @param age 表示输入的 {@code int}。 */ public void validateStudentAge(int age) { - if (studentValidateService != null) { - studentValidateService.validateStudentAge(age); + if (this.studentValidateService != null) { + this.studentValidateService.validateStudentAge(age); } } @@ -326,8 +326,8 @@ public void validateStudentAge(int age) { * @param age 表示输入的 {@code int}。 */ public void validateTeacherAge(int age) { - if (teacherValidateService != null) { - teacherValidateService.validateTeacherAge(age); + if (this.teacherValidateService != null) { + this.teacherValidateService.validateTeacherAge(age); } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java index a46b161bf..969feb4c8 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/Employee.java @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2024-2025 Huawei Technologies Co., Ltd. All rights reserved. * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/