From 77f7d9aab86789638a6ccd287a4aea2abf4794f0 Mon Sep 17 00:00:00 2001 From: Adam Saghy Date: Fri, 15 Aug 2025 20:17:03 +0200 Subject: [PATCH] FINERACT-2326: Use Hibernate Validator --- .../org.apache.fineract.dependencies.gradle | 1 - fineract-cob/dependencies.gradle | 2 - fineract-core/dependencies.gradle | 1 - .../JakartaValidationExceptionMapper.java | 8 +- .../test/helper/ErrorMessageHelper.java | 2 +- fineract-provider/dependencies.gradle | 2 - .../BusinessDateValidationTest.java | 49 ++++++---- .../validation/config/ValidationConfig.java | 91 ------------------- .../constraints/LocalDateValidator.java | 2 +- .../constraints/LocaleValidator.java | 2 +- ...operties => ValidationMessages.properties} | 10 +- .../validation/messages_en.properties | 43 --------- .../constraints/LocalDateValidationTest.java | 43 ++++++--- .../constraints/LocaleValidationTest.java | 35 +++++-- 14 files changed, 95 insertions(+), 196 deletions(-) delete mode 100644 fineract-validation/src/main/java/org/apache/fineract/validation/config/ValidationConfig.java rename fineract-validation/src/main/resources/{fineract/validation/messages.properties => ValidationMessages.properties} (86%) delete mode 100644 fineract-validation/src/main/resources/fineract/validation/messages_en.properties diff --git a/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle b/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle index 572682811..4893dfe91 100644 --- a/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle +++ b/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle @@ -123,7 +123,6 @@ dependencyManagement { dependency 'jakarta.jms:jakarta.jms-api:3.1.0' dependency 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0' dependency 'org.glassfish.jaxb:jaxb-runtime:2.3.6' // Swagger needs exactly this version - dependency 'org.apache.bval:org.apache.bval.bundle:3.0.2' dependency 'joda-time:joda-time:2.13.1' dependency 'io.github.classgraph:classgraph:4.8.179' diff --git a/fineract-cob/dependencies.gradle b/fineract-cob/dependencies.gradle index 08d98b14c..1da8d6860 100644 --- a/fineract-cob/dependencies.gradle +++ b/fineract-cob/dependencies.gradle @@ -88,8 +88,6 @@ dependencies { // runtimeOnly dependencies are things that Fineract code has no direct compile time dependency on, but which must be present at run-time runtimeOnly( - 'org.apache.bval:org.apache.bval.bundle', - // Although fineract (at the time of writing) doesn't have any compile time dep. on httpclient, // it's useful to have this for the Spring Boot TestRestTemplate http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-rest-templates-test-utility 'org.apache.httpcomponents:httpclient' diff --git a/fineract-core/dependencies.gradle b/fineract-core/dependencies.gradle index c93be8e14..13ebd906d 100644 --- a/fineract-core/dependencies.gradle +++ b/fineract-core/dependencies.gradle @@ -87,7 +87,6 @@ dependencies { // runtimeOnly dependencies are things that Fineract code has no direct compile time dependency on, but which must be present at run-time runtimeOnly( - 'org.apache.bval:org.apache.bval.bundle', // Although fineract (at the time of writing) doesn't have any compile time dep. on httpclient, // it's useful to have this for the Spring Boot TestRestTemplate http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-rest-templates-test-utility diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/JakartaValidationExceptionMapper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/JakartaValidationExceptionMapper.java index 00980f0e5..49b8fa7b7 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/JakartaValidationExceptionMapper.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exceptionmapper/JakartaValidationExceptionMapper.java @@ -30,8 +30,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.exception.ErrorHandler; -import org.springframework.context.MessageSource; -import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.stereotype.Component; @Slf4j @@ -40,8 +38,6 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor public class JakartaValidationExceptionMapper implements FineractExceptionMapper, ExceptionMapper { - private final MessageSource messageSource; - @Override public Response toResponse(final ConstraintViolationException exception) { log.warn("Exception occurred", ErrorHandler.findMostSpecificException(exception)); @@ -61,9 +57,7 @@ public class JakartaValidationExceptionMapper implements FineractExceptionMapper final String messageTemplate = violation.getMessageTemplate(); final String messageKey = messageTemplate.replace("{", "").replace("}", ""); - final String interpolatedMessage = messageSource.getMessage(messageKey, null, LocaleContextHolder.getLocale()); - - return ApiParameterError.parameterError(messageKey, interpolatedMessage, violation.getPropertyPath().toString()); + return ApiParameterError.parameterError(messageKey, violation.getMessage(), violation.getPropertyPath().toString()); }).toList(); } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java index 0a8767378..737812629 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java @@ -64,7 +64,7 @@ public final class ErrorMessageHelper { } public static String setIncorrectBusinessDateMandatoryFailure() { - return "The parameter 'date' is mandatory: '${validatedValue}'."; + return "The parameter 'date' is mandatory."; } public static String setCurrencyEmptyValueFailure() { diff --git a/fineract-provider/dependencies.gradle b/fineract-provider/dependencies.gradle index 462689794..6c112afc6 100644 --- a/fineract-provider/dependencies.gradle +++ b/fineract-provider/dependencies.gradle @@ -186,8 +186,6 @@ dependencies { // runtimeOnly dependencies are things that Fineract code has no direct compile time dependency on, but which must be present at run-time runtimeOnly( - 'org.apache.bval:org.apache.bval.bundle', - // Although fineract (at the time of writing) doesn't have any compile time dep. on httpclient, // it's useful to have this for the Spring Boot TestRestTemplate http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-rest-templates-test-utility 'org.apache.httpcomponents:httpclient' diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/validation/BusinessDateValidationTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/validation/BusinessDateValidationTest.java index 761911c03..e26564248 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/validation/BusinessDateValidationTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/businessdate/validation/BusinessDateValidationTest.java @@ -20,21 +20,36 @@ package org.apache.fineract.infrastructure.businessdate.validation; import static org.assertj.core.api.Assertions.assertThat; +import jakarta.validation.Validation; +import jakarta.validation.Validator; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.infrastructure.businessdate.data.BusinessDateUpdateRequest; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; -import org.apache.fineract.validation.config.ValidationConfig; +import org.hibernate.validator.HibernateValidator; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; -import org.springframework.validation.Validator; @Slf4j @SpringBootTest -@ContextConfiguration(classes = { ValidationConfig.class }) +@ContextConfiguration(classes = { BusinessDateValidationTest.TestConfig.class }) class BusinessDateValidationTest { + @Configuration + @Import({ MessageSourceAutoConfiguration.class }) + static class TestConfig { + + @Bean + public jakarta.validation.Validator validator() { + return Validation.byProvider(HibernateValidator.class).configure().buildValidatorFactory().getValidator(); + } + } + @Autowired private Validator validator; @@ -42,14 +57,14 @@ class BusinessDateValidationTest { void invalidAllBlank() { var request = BusinessDateUpdateRequest.builder().dateFormat("").type(null).date(" ").locale(null).build(); - var errors = validator.validateObject(request); + var errors = validator.validate(request); - assertThat(errors.getFieldErrorCount()).isEqualTo(5); + assertThat(errors).hasSize(6); - assertThat(errors.getFieldErrors()).anyMatch(e -> e.getField().equals("date")); - assertThat(errors.getFieldErrors()).anyMatch(e -> e.getField().equals("dateFormat")); - assertThat(errors.getFieldErrors()).anyMatch(e -> e.getField().equals("locale")); - assertThat(errors.getFieldErrors()).anyMatch(e -> e.getField().equals("type")); + assertThat(errors).anyMatch(e -> e.getPropertyPath().toString().equals("date")); + assertThat(errors).anyMatch(e -> e.getPropertyPath().toString().equals("dateFormat")); + assertThat(errors).anyMatch(e -> e.getPropertyPath().toString().equals("locale")); + assertThat(errors).anyMatch(e -> e.getPropertyPath().toString().equals("type")); } @Test @@ -57,11 +72,11 @@ class BusinessDateValidationTest { var request = BusinessDateUpdateRequest.builder().dateFormat("dd-MM-yyyy").type(BusinessDateType.BUSINESS_DATE).date("12-05-2025") .locale("INVALID").build(); - var errors = validator.validateObject(request); + var errors = validator.validate(request); - assertThat(errors.getFieldErrorCount()).isEqualTo(1); + assertThat(errors).hasSize(1); - assertThat(errors.getFieldErrors()).anyMatch(e -> e.getField().equals("locale")); + assertThat(errors).anyMatch(e -> e.getPropertyPath().toString().equals("locale")); } @Test @@ -69,11 +84,11 @@ class BusinessDateValidationTest { var request = BusinessDateUpdateRequest.builder().dateFormat("dd/MM/yyyy").type(BusinessDateType.BUSINESS_DATE).date("12-05-2025") .locale("en").build(); - var errors = validator.validateObject(request); + var errors = validator.validate(request); - assertThat(errors.getErrorCount()).isEqualTo(1); + assertThat(errors).hasSize(1); - assertThat(errors.getAllErrors()).anyMatch(e -> "Wrong local date fields.".equals(e.getDefaultMessage())); + assertThat(errors).anyMatch(e -> "Wrong local date fields.".equals(e.getMessage())); } @Test @@ -81,8 +96,8 @@ class BusinessDateValidationTest { var request = BusinessDateUpdateRequest.builder().dateFormat("dd-MM-yyyy").type(BusinessDateType.BUSINESS_DATE).date("12-05-2025") .locale("en").build(); - var errors = validator.validateObject(request); + var errors = validator.validate(request); - assertThat(errors.getFieldErrorCount()).isEqualTo(0); + assertThat(errors).hasSize(0); } } diff --git a/fineract-validation/src/main/java/org/apache/fineract/validation/config/ValidationConfig.java b/fineract-validation/src/main/java/org/apache/fineract/validation/config/ValidationConfig.java deleted file mode 100644 index e1e55b4c7..000000000 --- a/fineract-validation/src/main/java/org/apache/fineract/validation/config/ValidationConfig.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.validation.config; - -import jakarta.validation.MessageInterpolator; -import java.util.Locale; -import java.util.regex.Pattern; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator; -import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; -import org.springframework.context.MessageSource; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.validation.Validator; -import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; -import org.springframework.validation.beanvalidation.MessageSourceResourceBundleLocator; -import yakworks.i18n.icu.ICUBundleMessageSource; - -@Slf4j -@RequiredArgsConstructor -@Configuration -public class ValidationConfig { - - @Bean - public MessageSource messageSource() { - var messageSource = new ICUBundleMessageSource(); - messageSource.setBasenames("classpath:fineract/validation/messages"); - messageSource.setCacheSeconds(3600); - messageSource.setDefaultEncoding("UTF-8"); - - return messageSource; - } - - @Bean - public MessageInterpolator messageInterpolator() { - var resourceBundleLocator = new MessageSourceResourceBundleLocator(messageSource()); - var messageInterpolator = new ResourceBundleMessageInterpolator(resourceBundleLocator); - return new RecursiveLocaleContextMessageInterpolator(messageInterpolator); - } - - @Bean - @Primary - public Validator validator() { - var localValidatorFactoryBean = new LocalValidatorFactoryBean(); - localValidatorFactoryBean.setMessageInterpolator(messageInterpolator()); - - return localValidatorFactoryBean; - } - - private static final class RecursiveLocaleContextMessageInterpolator extends AbstractMessageInterpolator { - - private static final Pattern PATTERN_PLACEHOLDER = Pattern.compile("\\{([^}]+)\\}"); - - private final MessageInterpolator interpolator; - - private RecursiveLocaleContextMessageInterpolator(MessageInterpolator interpolator) { - this.interpolator = interpolator; - } - - @Override - public String interpolate(MessageInterpolator.Context context, Locale locale, String message) { - int level = 0; - while (containsPlaceholder(message) && (level++ < 2)) { - message = this.interpolator.interpolate(message, context, locale); - } - return message; - } - - private boolean containsPlaceholder(String code) { - return PATTERN_PLACEHOLDER.matcher(code).find(); - } - } -} diff --git a/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocalDateValidator.java b/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocalDateValidator.java index 7bb4eb81f..71fd64564 100644 --- a/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocalDateValidator.java +++ b/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocalDateValidator.java @@ -30,7 +30,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @Slf4j -class LocalDateValidator implements ConstraintValidator { +public class LocalDateValidator implements ConstraintValidator { private String dateField; private String formatField; diff --git a/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocaleValidator.java b/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocaleValidator.java index 664559524..6a3b515d6 100644 --- a/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocaleValidator.java +++ b/fineract-validation/src/main/java/org/apache/fineract/validation/constraints/LocaleValidator.java @@ -23,7 +23,7 @@ import jakarta.validation.ConstraintValidatorContext; import java.util.Arrays; import org.apache.commons.lang3.StringUtils; -class LocaleValidator implements ConstraintValidator { +public class LocaleValidator implements ConstraintValidator { @Override public boolean isValid(String value, ConstraintValidatorContext context) { diff --git a/fineract-validation/src/main/resources/fineract/validation/messages.properties b/fineract-validation/src/main/resources/ValidationMessages.properties similarity index 86% rename from fineract-validation/src/main/resources/fineract/validation/messages.properties rename to fineract-validation/src/main/resources/ValidationMessages.properties index a4e53db4d..fb0a4f20c 100644 --- a/fineract-validation/src/main/resources/fineract/validation/messages.properties +++ b/fineract-validation/src/main/resources/ValidationMessages.properties @@ -24,14 +24,14 @@ org.apache.fineract.validation.locale=The parameter `locale` has an invalid lang ## Business Date -org.apache.fineract.businessdate.date-format.not-blank=The parameter 'dateFormat' is mandatory: '${validatedValue}'. -org.apache.fineract.businessdate.type.not-null=The parameter 'type' is mandatory: '${validatedValue}'. -org.apache.fineract.businessdate.date.not-blank=The parameter 'date' is mandatory: '${validatedValue}'. -org.apache.fineract.businessdate.locale.not-blank=The parameter 'locale' is mandatory: '${validatedValue}'. +org.apache.fineract.businessdate.date-format.not-blank=The parameter 'dateFormat' is mandatory. +org.apache.fineract.businessdate.type.not-null=The parameter 'type' is mandatory. +org.apache.fineract.businessdate.date.not-blank=The parameter 'date' is mandatory. +org.apache.fineract.businessdate.locale.not-blank=The parameter 'locale' is mandatory. # External Events -org.apache.fineract.externalevent.configurations.not-null=The parameter 'externalEventConfigurations' is mandatory: '${validatedValue}'. +org.apache.fineract.externalevent.configurations.not-null=The parameter 'externalEventConfigurations' is mandatory. # Cache diff --git a/fineract-validation/src/main/resources/fineract/validation/messages_en.properties b/fineract-validation/src/main/resources/fineract/validation/messages_en.properties deleted file mode 100644 index a4e53db4d..000000000 --- a/fineract-validation/src/main/resources/fineract/validation/messages_en.properties +++ /dev/null @@ -1,43 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -# Validation - -org.apache.fineract.validation.local-date=Wrong local date fields. -org.apache.fineract.validation.locale=The parameter `locale` has an invalid language value: `${validatedValue}`. - -## Business Date - -org.apache.fineract.businessdate.date-format.not-blank=The parameter 'dateFormat' is mandatory: '${validatedValue}'. -org.apache.fineract.businessdate.type.not-null=The parameter 'type' is mandatory: '${validatedValue}'. -org.apache.fineract.businessdate.date.not-blank=The parameter 'date' is mandatory: '${validatedValue}'. -org.apache.fineract.businessdate.locale.not-blank=The parameter 'locale' is mandatory: '${validatedValue}'. - -# External Events - -org.apache.fineract.externalevent.configurations.not-null=The parameter 'externalEventConfigurations' is mandatory: '${validatedValue}'. - -# Cache - -org.apache.fineract.cache.cache-type.not-null=The parameter 'cacheType' is mandatory. - -# Currency - -org.apache.fineract.organisation.monetary.currencies.not-null=The parameter 'currencies' is mandatory. -org.apache.fineract.organisation.monetary.currencies.not-empty=The parameter 'currencies' cannot be empty. diff --git a/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocalDateValidationTest.java b/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocalDateValidationTest.java index 105948470..4eadf5906 100644 --- a/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocalDateValidationTest.java +++ b/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocalDateValidationTest.java @@ -20,23 +20,38 @@ package org.apache.fineract.validation.constraints; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import jakarta.validation.Validation; +import jakarta.validation.Validator; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.fineract.validation.config.ValidationConfig; +import org.hibernate.validator.HibernateValidator; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; -import org.springframework.validation.Validator; @Slf4j @SpringBootTest -@ContextConfiguration(classes = { ValidationConfig.class }) +@ContextConfiguration(classes = { LocalDateValidationTest.TestConfig.class }) class LocalDateValidationTest { + @Configuration + @Import({ MessageSourceAutoConfiguration.class }) + static class TestConfig { + + @Bean + public Validator validator() { + return Validation.byProvider(HibernateValidator.class).configure().buildValidatorFactory().getValidator(); + } + } + @Autowired private Validator validator; @@ -44,42 +59,42 @@ class LocalDateValidationTest { void invalidAllBlank() { var request = LocalDateModel.builder().format("").date(" ").locale(null).build(); - var errors = validator.validateObject(request); + var errors = validator.validate(request); - assertThat(errors.getAllErrors()).hasSize(1); + assertThat(errors).hasSize(1); - assertThat(errors.getAllErrors()).allMatch(e -> "Wrong local date fields.".equals(e.getDefaultMessage())); + assertThat(errors).allMatch(e -> "Wrong local date fields.".equals(e.getMessage())); } @Test void invalidLocaleFormat() { var request = LocalDateModel.builder().format("dd-MM-yyyy").date("12-05-2025").locale("").build(); - var errors = validator.validateObject(request); + var errors = validator.validate(request); - assertThat(errors.getAllErrors()).hasSize(1); + assertThat(errors).hasSize(1); - assertThat(errors.getAllErrors()).allMatch(e -> "Wrong local date fields.".equals(e.getDefaultMessage())); + assertThat(errors).allMatch(e -> "Wrong local date fields.".equals(e.getMessage())); } @Test void invalidDateFormat() { var request = LocalDateModel.builder().format("dd/MM/yyyy").date("12-05-2025").locale("en").build(); - var errors = validator.validateObject(request); + var errors = validator.validate(request); - assertThat(errors.getAllErrors()).hasSize(1); + assertThat(errors).hasSize(1); - assertThat(errors.getAllErrors()).allMatch(e -> "Wrong local date fields.".equals(e.getDefaultMessage())); + assertThat(errors).allMatch(e -> "Wrong local date fields.".equals(e.getMessage())); } @Test void valid() { var request = LocalDateModel.builder().format("dd-MM-yyyy").date("12-05-2025").locale("en").build(); - var errors = validator.validateObject(request); + var errors = validator.validate(request); - assertThat(errors.getAllErrors()).isEmpty(); + assertThat(errors).isEmpty(); } @Builder diff --git a/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocaleValidationTest.java b/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocaleValidationTest.java index 192f59945..d9cd382ae 100644 --- a/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocaleValidationTest.java +++ b/fineract-validation/src/test/java/org/apache/fineract/validation/constraints/LocaleValidationTest.java @@ -20,25 +20,40 @@ package org.apache.fineract.validation.constraints; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import jakarta.validation.Validation; +import jakarta.validation.Validator; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.fineract.validation.config.ValidationConfig; +import org.hibernate.validator.HibernateValidator; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; -import org.springframework.validation.Validator; @Slf4j @SpringBootTest -@ContextConfiguration(classes = { ValidationConfig.class }) +@ContextConfiguration(classes = { LocalDateValidationTest.TestConfig.class }) class LocaleValidationTest { + @Configuration + @Import({ MessageSourceAutoConfiguration.class }) + static class TestConfig { + + @Bean + public jakarta.validation.Validator validator() { + return Validation.byProvider(HibernateValidator.class).configure().buildValidatorFactory().getValidator(); + } + } + @Autowired private Validator validator; @@ -46,11 +61,11 @@ class LocaleValidationTest { void invalidBlank() { var request = LocaleModel.builder().locale(null).build(); - var errors = validator.validateObject(request); + var errors = validator.validate(request); - assertThat(errors.getFieldErrorCount()).isEqualTo(1); + assertThat(errors).hasSize(1); - assertThat(errors.getFieldErrors()).anyMatch(e -> e.getField().equals("locale")); + assertThat(errors).anyMatch(e -> e.getPropertyPath().toString().equals("locale")); } @ParameterizedTest @@ -62,8 +77,8 @@ class LocaleValidationTest { }) void invalidFormats(String locale) { var request = LocaleModel.builder().locale(locale).build(); - var errors = validator.validateObject(request); - assertThat(errors.getFieldErrorCount()).as("Expected locale '%s' to be invalid but it was valid", locale).isGreaterThan(0); + var errors = validator.validate(request); + assertThat(errors).as("Expected locale '%s' to be invalid but it was valid", locale).hasSize(1); } @ParameterizedTest @@ -74,8 +89,8 @@ class LocaleValidationTest { }) void validLocales(String locale) { var request = LocaleModel.builder().locale(locale).build(); - var errors = validator.validateObject(request); - assertThat(errors.getFieldErrorCount()).as("Expected locale '%s' to be valid but it was invalid", locale).isZero(); + var errors = validator.validate(request); + assertThat(errors).as("Expected locale '%s' to be valid but it was invalid", locale).hasSize(0); } @Builder