У меня приложение Gradle Spring Boot, работающее на Java 11 с использованием Hibernate Validator . Недавно я начал использовать несколько JAR-файлов, которые определяют свои собственные файлы ValidationMessages.properties
с сообщениями по умолчанию для своих собственных пользовательских аннотаций проверки. Для поддержки этого я использую встроенную функциональность PlatformResourceBundleLocator для объединения ValidationMessages.properties
файлов из нескольких файлов JAR в один пакет:
@Configuration
public class ValidationConfig {
@Bean
public LocalValidatorFactoryBean validator() {
ResourceBundle.clearCache();
PlatformResourceBundleLocator resourceBundleLocator =
new PlatformResourceBundleLocator(ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES, null, true);
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
factoryBean.setMessageInterpolator(new ResourceBundleMessageInterpolator(resourceBundleLocator));
return factoryBean;
}
}
jar1: ValidationMessages.properties
com.example.CustomValidation1.message=My custom message 1
jar2: ValidationMessages.properties
com.example.CustomValidation2.message=My custom message 2
Я использую эти проверки в моих классах обслуживания с использованием аннотации Spring @Validated
:
@Validated
@Service
public class MyService {
public void myMethod(@Valid @CustomValidation1 @CustomValidation2 MyInput input) {
// do something with input
}
}
Эта функция работает должным образом, когда я запускаю приложение напрямую.
В проекте имеется большое количество модульных и интеграционных тестов, которые я запускаю из Gradle, некоторые из которых проверяют сообщение проверки, например:
@RunWith(SpringRunner.class)
@Import({MyService.class, ValidationConfig.class, ValidationAutoConfiguration.class})
public class MyServiceTest {
@Autowired
private MyService service;
@Test
public void testValidation() {
MyInput input = inputWhichFailsBothValidations();
try {
service.myMethod(updateRequests);
fail("Expected a ConstraintViolationException to be thrown");
} catch (ConstraintViolationException e) {
assertEquals(Set.of("My custom message 1", "My custom message 2"), e.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage).collect(Collectors.toSet()));
}
}
}
Проект также содержит ряд более старых тестов, некоторые из которых используют валидации, но не полагаются на новую функциональность совокупного сообщения и не используют ее. Ни один из более старых тестов не основывается на предыдущем неагрегировании ValidationMessages.properties
, хотя, поскольку они предшествуют его использованию, они не обязательно его конфигурируют.
Тесты работают, как и ожидалось, локально, при этом сообщения проверки выводятся из какой бы файл JAR ValidationMessages.properties
не содержал соответствующий ключ. Однако, когда тесты моего проекта выполняются на сервере сборки с помощью инструмента непрерывной интеграции Jenkins , вышеприведенный тест не пройден.
java.lang.AssertionError:
Expected :[My custom message 1, My custom message 2]
Actual :[My custom message 1, {com.example.CustomValidation2.message}]
Немного окунувшись в проблему, оказывается, что используется только один из ValidationMessages.properties
, а другой - нет. Я предполагаю, что тесты в Дженкинсе выполняются в другом порядке, нежели локально. По какой-то причине порядок тестирования должен каким-то образом зависеть от использования свойства сообщения, несмотря на тот факт, что я могу подтвердить посредством регистрации, что настроенный PlatformResourceBundleLocator
используется для вышеуказанного теста. Поддержка этой теории заключается в том, что когда я настраиваю Jenkins для запуска только одного теста, а не всех тестов, он проходит.
Хотя я нигде не вижу его документированного, из исходного кода Hibernate Validator Я вижу, что агрегация пакетов ресурсов отключена в двух случаях: в среде Google App Engine и при запуске Hibernate Validator с именем Java 9 с именованным модулем. Ни один из этих случаев не подходит, и я подтвердил с помощью регистрации, что агрегация включена.
Почему это происходит, и как я могу это исправить, чтобы инфраструктура проверки использовала мои агрегированные сообщения проверки независимо от того, где мои тесты запущены?
В данный момент я нахожусь на Spring Boot 2.2.4.RELEASE с Hibernate Validator 6.0.18.Final.